@fluixi/reactive 1.0.0-alpha.100

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 (211) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +280 -0
  3. package/dist/cdn/reactive.cjs +2803 -0
  4. package/dist/cdn/reactive.d.ts +11 -0
  5. package/dist/cdn/reactive.d.ts.map +1 -0
  6. package/dist/cdn/reactive.global.js +2 -0
  7. package/dist/cdn/reactive.js +10 -0
  8. package/dist/cdn/reactive.mjs +2787 -0
  9. package/dist/cdn/signal.cjs +299 -0
  10. package/dist/cdn/signal.d.ts +19 -0
  11. package/dist/cdn/signal.d.ts.map +1 -0
  12. package/dist/cdn/signal.global.js +2 -0
  13. package/dist/cdn/signal.js +18 -0
  14. package/dist/cdn/signal.mjs +276 -0
  15. package/dist/index.cjs +2803 -0
  16. package/dist/index.d.ts +2 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +1 -0
  19. package/dist/index.mjs +2787 -0
  20. package/dist/lib/index.cjs +2804 -0
  21. package/dist/lib/index.d.ts +8 -0
  22. package/dist/lib/index.d.ts.map +1 -0
  23. package/dist/lib/index.js +11 -0
  24. package/dist/lib/index.mjs +2789 -0
  25. package/dist/lib/observable/index.cjs +386 -0
  26. package/dist/lib/observable/index.d.ts +4 -0
  27. package/dist/lib/observable/index.d.ts.map +1 -0
  28. package/dist/lib/observable/index.js +3 -0
  29. package/dist/lib/observable/index.mjs +364 -0
  30. package/dist/lib/observable/observable.cjs +384 -0
  31. package/dist/lib/observable/observable.d.ts +246 -0
  32. package/dist/lib/observable/observable.d.ts.map +1 -0
  33. package/dist/lib/observable/observable.js +268 -0
  34. package/dist/lib/observable/observable.mjs +361 -0
  35. package/dist/lib/observable/subscription.cjs +180 -0
  36. package/dist/lib/observable/subscription.d.ts +58 -0
  37. package/dist/lib/observable/subscription.d.ts.map +1 -0
  38. package/dist/lib/observable/subscription.js +177 -0
  39. package/dist/lib/observable/subscription.mjs +157 -0
  40. package/dist/lib/observable/types.cjs +18 -0
  41. package/dist/lib/observable/types.d.ts +44 -0
  42. package/dist/lib/observable/types.d.ts.map +1 -0
  43. package/dist/lib/observable/types.js +1 -0
  44. package/dist/lib/observable/types.mjs +0 -0
  45. package/dist/lib/predicates.cjs +44 -0
  46. package/dist/lib/predicates.d.ts +37 -0
  47. package/dist/lib/predicates.d.ts.map +1 -0
  48. package/dist/lib/predicates.js +62 -0
  49. package/dist/lib/predicates.mjs +23 -0
  50. package/dist/lib/signal/api.cjs +592 -0
  51. package/dist/lib/signal/api.d.ts +227 -0
  52. package/dist/lib/signal/api.d.ts.map +1 -0
  53. package/dist/lib/signal/api.js +228 -0
  54. package/dist/lib/signal/api.mjs +569 -0
  55. package/dist/lib/signal/cached-resource.cjs +726 -0
  56. package/dist/lib/signal/cached-resource.d.ts +86 -0
  57. package/dist/lib/signal/cached-resource.d.ts.map +1 -0
  58. package/dist/lib/signal/cached-resource.js +250 -0
  59. package/dist/lib/signal/cached-resource.mjs +704 -0
  60. package/dist/lib/signal/graph/children.cjs +326 -0
  61. package/dist/lib/signal/graph/children.d.ts +2 -0
  62. package/dist/lib/signal/graph/children.d.ts.map +1 -0
  63. package/dist/lib/signal/graph/children.js +30 -0
  64. package/dist/lib/signal/graph/children.mjs +303 -0
  65. package/dist/lib/signal/graph/compat.cjs +590 -0
  66. package/dist/lib/signal/graph/compat.d.ts +66 -0
  67. package/dist/lib/signal/graph/compat.d.ts.map +1 -0
  68. package/dist/lib/signal/graph/compat.js +197 -0
  69. package/dist/lib/signal/graph/compat.mjs +568 -0
  70. package/dist/lib/signal/graph/core.cjs +295 -0
  71. package/dist/lib/signal/graph/core.d.ts +99 -0
  72. package/dist/lib/signal/graph/core.d.ts.map +1 -0
  73. package/dist/lib/signal/graph/core.js +268 -0
  74. package/dist/lib/signal/graph/core.mjs +273 -0
  75. package/dist/lib/signal/graph/debounced.cjs +680 -0
  76. package/dist/lib/signal/graph/debounced.d.ts +67 -0
  77. package/dist/lib/signal/graph/debounced.d.ts.map +1 -0
  78. package/dist/lib/signal/graph/debounced.js +92 -0
  79. package/dist/lib/signal/graph/debounced.mjs +657 -0
  80. package/dist/lib/signal/graph/derived.cjs +508 -0
  81. package/dist/lib/signal/graph/derived.d.ts +14 -0
  82. package/dist/lib/signal/graph/derived.d.ts.map +1 -0
  83. package/dist/lib/signal/graph/derived.js +65 -0
  84. package/dist/lib/signal/graph/derived.mjs +485 -0
  85. package/dist/lib/signal/graph/detect.cjs +66 -0
  86. package/dist/lib/signal/graph/detect.d.ts +17 -0
  87. package/dist/lib/signal/graph/detect.d.ts.map +1 -0
  88. package/dist/lib/signal/graph/detect.js +39 -0
  89. package/dist/lib/signal/graph/detect.mjs +45 -0
  90. package/dist/lib/signal/graph/error-boundary.cjs +313 -0
  91. package/dist/lib/signal/graph/error-boundary.d.ts +16 -0
  92. package/dist/lib/signal/graph/error-boundary.d.ts.map +1 -0
  93. package/dist/lib/signal/graph/error-boundary.js +34 -0
  94. package/dist/lib/signal/graph/error-boundary.mjs +290 -0
  95. package/dist/lib/signal/graph/index.cjs +305 -0
  96. package/dist/lib/signal/graph/index.d.ts +22 -0
  97. package/dist/lib/signal/graph/index.d.ts.map +1 -0
  98. package/dist/lib/signal/graph/index.js +21 -0
  99. package/dist/lib/signal/graph/index.mjs +283 -0
  100. package/dist/lib/signal/graph/observe.cjs +198 -0
  101. package/dist/lib/signal/graph/observe.d.ts +185 -0
  102. package/dist/lib/signal/graph/observe.d.ts.map +1 -0
  103. package/dist/lib/signal/graph/observe.js +198 -0
  104. package/dist/lib/signal/graph/observe.mjs +175 -0
  105. package/dist/lib/signal/graph/resource.cjs +632 -0
  106. package/dist/lib/signal/graph/resource.d.ts +39 -0
  107. package/dist/lib/signal/graph/resource.d.ts.map +1 -0
  108. package/dist/lib/signal/graph/resource.js +165 -0
  109. package/dist/lib/signal/graph/resource.mjs +609 -0
  110. package/dist/lib/signal/graph/runtime.cjs +522 -0
  111. package/dist/lib/signal/graph/runtime.d.ts +80 -0
  112. package/dist/lib/signal/graph/runtime.d.ts.map +1 -0
  113. package/dist/lib/signal/graph/runtime.js +358 -0
  114. package/dist/lib/signal/graph/runtime.mjs +499 -0
  115. package/dist/lib/signal/graph/signal-next.cjs +1249 -0
  116. package/dist/lib/signal/graph/signal-next.d.ts +38 -0
  117. package/dist/lib/signal/graph/signal-next.d.ts.map +1 -0
  118. package/dist/lib/signal/graph/signal-next.js +44 -0
  119. package/dist/lib/signal/graph/signal-next.mjs +1227 -0
  120. package/dist/lib/signal/graph/ssr-hooks.cjs +89 -0
  121. package/dist/lib/signal/graph/ssr-hooks.d.ts +51 -0
  122. package/dist/lib/signal/graph/ssr-hooks.d.ts.map +1 -0
  123. package/dist/lib/signal/graph/ssr-hooks.js +80 -0
  124. package/dist/lib/signal/graph/ssr-hooks.mjs +68 -0
  125. package/dist/lib/signal/graph/state.cjs +72 -0
  126. package/dist/lib/signal/graph/state.d.ts +76 -0
  127. package/dist/lib/signal/graph/state.d.ts.map +1 -0
  128. package/dist/lib/signal/graph/state.js +99 -0
  129. package/dist/lib/signal/graph/state.mjs +49 -0
  130. package/dist/lib/signal/graph/suspense.cjs +313 -0
  131. package/dist/lib/signal/graph/suspense.d.ts +13 -0
  132. package/dist/lib/signal/graph/suspense.d.ts.map +1 -0
  133. package/dist/lib/signal/graph/suspense.js +36 -0
  134. package/dist/lib/signal/graph/suspense.mjs +290 -0
  135. package/dist/lib/signal/index-legacy.cjs +2582 -0
  136. package/dist/lib/signal/index-legacy.d.ts +12 -0
  137. package/dist/lib/signal/index-legacy.d.ts.map +1 -0
  138. package/dist/lib/signal/index-legacy.js +11 -0
  139. package/dist/lib/signal/index-legacy.mjs +2560 -0
  140. package/dist/lib/signal/index.cjs +1350 -0
  141. package/dist/lib/signal/index.d.ts +19 -0
  142. package/dist/lib/signal/index.d.ts.map +1 -0
  143. package/dist/lib/signal/index.js +19 -0
  144. package/dist/lib/signal/index.mjs +1328 -0
  145. package/dist/lib/signal/list.cjs +561 -0
  146. package/dist/lib/signal/list.d.ts +39 -0
  147. package/dist/lib/signal/list.d.ts.map +1 -0
  148. package/dist/lib/signal/list.js +172 -0
  149. package/dist/lib/signal/list.mjs +538 -0
  150. package/dist/lib/signal/resource-api.cjs +638 -0
  151. package/dist/lib/signal/resource-api.d.ts +19 -0
  152. package/dist/lib/signal/resource-api.d.ts.map +1 -0
  153. package/dist/lib/signal/resource-api.js +27 -0
  154. package/dist/lib/signal/resource-api.mjs +615 -0
  155. package/dist/lib/signal/signal.cjs +2035 -0
  156. package/dist/lib/signal/signal.d.ts +303 -0
  157. package/dist/lib/signal/signal.d.ts.map +1 -0
  158. package/dist/lib/signal/signal.js +1233 -0
  159. package/dist/lib/signal/signal.mjs +2012 -0
  160. package/dist/lib/signal/types.cjs +38 -0
  161. package/dist/lib/signal/types.d.ts +133 -0
  162. package/dist/lib/signal/types.d.ts.map +1 -0
  163. package/dist/lib/signal/types.js +38 -0
  164. package/dist/lib/signal/types.mjs +17 -0
  165. package/dist/lib/signal/utilities.cjs +1024 -0
  166. package/dist/lib/signal/utilities.d.ts +247 -0
  167. package/dist/lib/signal/utilities.d.ts.map +1 -0
  168. package/dist/lib/signal/utilities.js +346 -0
  169. package/dist/lib/signal/utilities.mjs +1002 -0
  170. package/dist/lib/store/api.cjs +662 -0
  171. package/dist/lib/store/api.d.ts +40 -0
  172. package/dist/lib/store/api.d.ts.map +1 -0
  173. package/dist/lib/store/api.js +63 -0
  174. package/dist/lib/store/api.mjs +646 -0
  175. package/dist/lib/store/index.cjs +741 -0
  176. package/dist/lib/store/index.d.ts +16 -0
  177. package/dist/lib/store/index.d.ts.map +1 -0
  178. package/dist/lib/store/index.js +13 -0
  179. package/dist/lib/store/index.mjs +726 -0
  180. package/dist/lib/store/setter.types.cjs +18 -0
  181. package/dist/lib/store/setter.types.d.ts +131 -0
  182. package/dist/lib/store/setter.types.d.ts.map +1 -0
  183. package/dist/lib/store/setter.types.js +65 -0
  184. package/dist/lib/store/setter.types.mjs +0 -0
  185. package/dist/lib/store/store.cjs +708 -0
  186. package/dist/lib/store/store.d.ts +142 -0
  187. package/dist/lib/store/store.d.ts.map +1 -0
  188. package/dist/lib/store/store.js +812 -0
  189. package/dist/lib/store/store.mjs +694 -0
  190. package/dist/lib/store/types.cjs +18 -0
  191. package/dist/lib/store/types.d.ts +57 -0
  192. package/dist/lib/store/types.d.ts.map +1 -0
  193. package/dist/lib/store/types.js +1 -0
  194. package/dist/lib/store/types.mjs +0 -0
  195. package/dist/lib/store/utils.cjs +43 -0
  196. package/dist/lib/store/utils.d.ts +13 -0
  197. package/dist/lib/store/utils.d.ts.map +1 -0
  198. package/dist/lib/store/utils.js +29 -0
  199. package/dist/lib/store/utils.mjs +22 -0
  200. package/dist/lib/subject.cjs +450 -0
  201. package/dist/lib/subject.d.ts +14 -0
  202. package/dist/lib/subject.d.ts.map +1 -0
  203. package/dist/lib/subject.js +81 -0
  204. package/dist/lib/subject.mjs +427 -0
  205. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  206. package/dist/version.generated.cjs +27 -0
  207. package/dist/version.generated.d.ts +3 -0
  208. package/dist/version.generated.d.ts.map +1 -0
  209. package/dist/version.generated.js +3 -0
  210. package/dist/version.generated.mjs +7 -0
  211. package/package.json +115 -0
@@ -0,0 +1,313 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/lib/signal/graph/suspense.ts
21
+ var suspense_exports = {};
22
+ __export(suspense_exports, {
23
+ SuspenseContext: () => SuspenseContext,
24
+ createSuspenseBoundary: () => createSuspenseBoundary,
25
+ provideSuspense: () => provideSuspense
26
+ });
27
+ module.exports = __toCommonJS(suspense_exports);
28
+
29
+ // src/version.generated.ts
30
+ var VERSION = "1.0.0-alpha.100";
31
+
32
+ // src/lib/signal/graph/state.ts
33
+ var MAJOR = VERSION.split(".")[0];
34
+ var KEY = `__fluixi_signal_state_v${MAJOR}__`;
35
+ var VERSIONS_KEY = `__fluixi_signal_builds_v${MAJOR}__`;
36
+ var defaultSchedule = (run) => {
37
+ if (typeof queueMicrotask === "function") queueMicrotask(run);
38
+ else void Promise.resolve().then(run);
39
+ };
40
+ function defaults() {
41
+ return {
42
+ consumer: null,
43
+ untracked: false,
44
+ owner: null,
45
+ queue: [],
46
+ scheduled: false,
47
+ flushing: false,
48
+ batchDepth: 0,
49
+ hostSchedule: defaultSchedule,
50
+ onSuspend: null,
51
+ onError: null,
52
+ observer: null
53
+ };
54
+ }
55
+ var realm = globalThis;
56
+ function backfillState(existing) {
57
+ const fresh = defaults();
58
+ const target = existing;
59
+ for (const field of Object.keys(fresh)) {
60
+ if (!(field in existing)) target[field] = fresh[field];
61
+ }
62
+ return existing;
63
+ }
64
+ function claim() {
65
+ const existing = realm[KEY];
66
+ return existing ? backfillState(existing) : realm[KEY] = defaults();
67
+ }
68
+ var G = claim();
69
+ (realm[VERSIONS_KEY] ??= []).push(VERSION);
70
+
71
+ // src/lib/signal/graph/observe.ts
72
+ function observeReactiveNodes(next) {
73
+ G.observer = next;
74
+ return () => {
75
+ if (G.observer === next) G.observer = null;
76
+ };
77
+ }
78
+ var running = [];
79
+ var origin;
80
+ var currentScope;
81
+ function reportReactiveNode(report) {
82
+ const observer = G.observer;
83
+ if (observer) {
84
+ observer.created(
85
+ report.parents === void 0 ? { ...report, parents: running, origin: report.origin ?? origin, scope: report.scope ?? currentScope } : { ...report, scope: report.scope ?? currentScope }
86
+ );
87
+ }
88
+ }
89
+ function reportReactiveWrite(node, by) {
90
+ G.observer?.wrote?.(node, by);
91
+ }
92
+ function reportReactiveContextCreated(id) {
93
+ G.observer?.contextCreated?.(id);
94
+ }
95
+ function reportReactiveContext(id, kind, value) {
96
+ const observer = G.observer;
97
+ if (!observer?.context || !running.length) return;
98
+ observer.context(running[running.length - 1], id, kind, value);
99
+ }
100
+ function reportReactiveDispose(node) {
101
+ G.observer?.disposed?.(node);
102
+ }
103
+ var HOOK = "__FLUIXI_DEVTOOLS_HOOK__";
104
+ var hook = globalThis[HOOK];
105
+ if (typeof hook?.inject === "function") {
106
+ try {
107
+ hook.inject({ observeReactiveNodes, version: VERSION });
108
+ } catch {
109
+ }
110
+ }
111
+ function isObserved() {
112
+ return G.observer != null;
113
+ }
114
+
115
+ // src/lib/signal/graph/core.ts
116
+ var DIRTY = 2;
117
+ var Source = class {
118
+ constructor() {
119
+ /** Computeds, and watched leaves, that read this node. */
120
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
121
+ this.observers = null;
122
+ /** Watchers eagerly observing this node, which is how `runtime.ts` schedules effects. */
123
+ this.watchers = null;
124
+ /** Bumped whenever this node's value actually changes (equality-gated). */
125
+ this.version = 0;
126
+ }
127
+ /** Settle this node so a reader sees a current value/version. Overridden by Computed. */
128
+ updateIfNecessary() {
129
+ }
130
+ /** Link the current consumer (if any) as an observer of this node. */
131
+ track() {
132
+ if (G.untracked) return;
133
+ const consumer = G.consumer;
134
+ if (!consumer) return;
135
+ (this.observers ??= /* @__PURE__ */ new Set()).add(consumer);
136
+ (consumer.sources ??= /* @__PURE__ */ new Set()).add(this);
137
+ }
138
+ };
139
+ var State = class extends Source {
140
+ constructor(value, options) {
141
+ super();
142
+ this._value = value;
143
+ this._equals = options?.equals === false ? () => false : options?.equals ?? Object.is;
144
+ }
145
+ get() {
146
+ this.track();
147
+ return this._value;
148
+ }
149
+ set(next) {
150
+ if (this._equals(this._value, next)) return;
151
+ this._value = next;
152
+ this.version++;
153
+ reportReactiveWrite(this, G.consumer);
154
+ if (this.observers) for (const o of [...this.observers]) o.markDirty(DIRTY);
155
+ notifyWatchers(this);
156
+ }
157
+ /** Read without subscribing (peek). */
158
+ peek() {
159
+ return this._value;
160
+ }
161
+ };
162
+ function notifyWatchers(node) {
163
+ if (!node.watchers) return;
164
+ for (const w of [...node.watchers]) w._notify(node);
165
+ }
166
+
167
+ // src/lib/signal/graph/runtime.ts
168
+ function makeOwner(parent) {
169
+ return { cleanups: null, owned: null, parent, contexts: null };
170
+ }
171
+ function createContext(defaultValue, name) {
172
+ const id = Symbol(name ?? "context");
173
+ reportReactiveContextCreated(id);
174
+ const Provider = (props) => {
175
+ reportReactiveContext(id, "provide", props.value);
176
+ const parent = G.owner;
177
+ const owner = makeOwner(parent);
178
+ (owner.contexts = /* @__PURE__ */ new Map()).set(id, props.value);
179
+ if (parent) (parent.owned ??= []).push(owner);
180
+ G.owner = owner;
181
+ try {
182
+ return props.children;
183
+ } finally {
184
+ G.owner = parent;
185
+ }
186
+ };
187
+ return { id, defaultValue, Provider };
188
+ }
189
+ function readContextFrom(owner, context) {
190
+ let o = owner;
191
+ while (o) {
192
+ if (o.contexts && o.contexts.has(context.id)) return o.contexts.get(context.id);
193
+ o = o.parent;
194
+ }
195
+ return context.defaultValue;
196
+ }
197
+ function provide(context, value, fn) {
198
+ const owner = makeOwner(G.owner);
199
+ (owner.contexts = /* @__PURE__ */ new Map()).set(context.id, value);
200
+ if (G.owner) (G.owner.owned ??= []).push(owner);
201
+ const prev = G.owner;
202
+ G.owner = owner;
203
+ try {
204
+ return fn();
205
+ } finally {
206
+ G.owner = prev;
207
+ }
208
+ }
209
+ function setSuspendHandler(fn) {
210
+ G.onSuspend = fn;
211
+ }
212
+ function onCleanup(fn) {
213
+ if (!G.owner) return;
214
+ if (G.owner.disposed) {
215
+ fn();
216
+ return;
217
+ }
218
+ (G.owner.cleanups ??= []).push(fn);
219
+ }
220
+ function setScheduler(fn) {
221
+ G.hostSchedule = fn ?? ((run) => void Promise.resolve().then(run));
222
+ }
223
+ function flushSync() {
224
+ G.scheduled = false;
225
+ if (G.flushing) return;
226
+ G.flushing = true;
227
+ let guard = 0;
228
+ let failed = false;
229
+ let first;
230
+ try {
231
+ while (G.queue.length) {
232
+ if (++guard > 1e5) throw new Error("[fluixi] effect flush did not settle (cycle?)");
233
+ const batchOf = G.queue;
234
+ G.queue = [];
235
+ for (const e of batchOf) {
236
+ e.queued = false;
237
+ if (e.disposed) continue;
238
+ try {
239
+ e.run();
240
+ } catch (error) {
241
+ if (!failed) {
242
+ failed = true;
243
+ first = error;
244
+ }
245
+ }
246
+ }
247
+ }
248
+ } finally {
249
+ G.flushing = false;
250
+ }
251
+ if (failed) throw first;
252
+ }
253
+ function afterWrite() {
254
+ if (G.batchDepth === 0) flushSync();
255
+ }
256
+
257
+ // src/lib/signal/graph/compat.ts
258
+ setScheduler(() => {
259
+ });
260
+ var $SIGNAL = /* @__PURE__ */ Symbol.for("signal");
261
+ var $NODE = /* @__PURE__ */ Symbol.for("signal-node");
262
+ function createSignal(value, options) {
263
+ const state = new State(value, { equals: options?.equals });
264
+ const read = (() => state.get());
265
+ const write = ((next) => {
266
+ const v = typeof next === "function" ? next(state.peek()) : next;
267
+ state.set(v);
268
+ afterWrite();
269
+ return v;
270
+ });
271
+ Object.defineProperty(read, $SIGNAL, { value: true, enumerable: true });
272
+ Object.defineProperty(read, $NODE, {
273
+ value: {
274
+ get value() {
275
+ return state.peek();
276
+ },
277
+ get version() {
278
+ return state.version;
279
+ }
280
+ },
281
+ enumerable: false
282
+ });
283
+ reportReactiveNode({
284
+ kind: "signal",
285
+ node: state,
286
+ handle: read,
287
+ name: options?.name,
288
+ set: write
289
+ });
290
+ if (isObserved()) onCleanup(() => reportReactiveDispose(state));
291
+ return [read, write];
292
+ }
293
+
294
+ // src/lib/signal/graph/suspense.ts
295
+ var SuspenseContext = createContext();
296
+ setSuspendHandler((promise, owner) => {
297
+ const boundary = readContextFrom(owner, SuspenseContext);
298
+ if (!boundary) return;
299
+ boundary.increment();
300
+ promise.finally(() => boundary.decrement());
301
+ });
302
+ function createSuspenseBoundary() {
303
+ const [pending, setPending] = createSignal(0);
304
+ let count = 0;
305
+ return {
306
+ increment: () => setPending(count += 1),
307
+ decrement: () => setPending(count -= 1),
308
+ inFallback: () => pending() > 0
309
+ };
310
+ }
311
+ function provideSuspense(boundary, fn) {
312
+ return provide(SuspenseContext, boundary, fn);
313
+ }
@@ -0,0 +1,13 @@
1
+ export interface SuspenseBoundary {
2
+ increment(): void;
3
+ decrement(): void;
4
+ /** Reactive: true while any descendant read is still pending. */
5
+ inFallback(): boolean;
6
+ }
7
+ declare const SuspenseContext: import("./runtime.js").Context<SuspenseBoundary | undefined>;
8
+ /** Create a boundary's reactive state (pending counter + inFallback). */
9
+ export declare function createSuspenseBoundary(): SuspenseBoundary;
10
+ /** Run `fn` (the boundary's children) under a Suspense scope, so suspended reads inside report to `boundary`. */
11
+ export declare function provideSuspense<R>(boundary: SuspenseBoundary, fn: () => R): R;
12
+ export { SuspenseContext };
13
+ //# sourceMappingURL=suspense.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suspense.d.ts","sourceRoot":"","sources":["../../../../src/lib/signal/graph/suspense.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,IAAI,IAAI,CAAC;IAClB,SAAS,IAAI,IAAI,CAAC;IAClB,iEAAiE;IACjE,UAAU,IAAI,OAAO,CAAC;CACvB;AAED,QAAA,MAAM,eAAe,8DAAgD,CAAC;AAUtE,yEAAyE;AACzE,wBAAgB,sBAAsB,IAAI,gBAAgB,CAQzD;AAED,iHAAiH;AACjH,wBAAgB,eAAe,CAAC,CAAC,EAAE,QAAQ,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAE7E;AAED,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Suspense ported onto the TC39 core (additive; legacy signal.ts untouched).
3
+ *
4
+ * A Suspense boundary is just a context carrying a pending counter. A suspended read
5
+ * (createResource while pending throws its promise) bubbles to the runtime effect's run(),
6
+ * which calls the injected suspend handler registered here, it finds the nearest
7
+ * boundary (via the effect's owner chain) and increments it; the promise settling
8
+ * decrements it. The effect itself re-runs through normal reactivity once the
9
+ * resource's state signal changes, so the resolved content replaces the fallback.
10
+ */
11
+ import { createContext, provide, readContextFrom, setSuspendHandler, } from './runtime.js';
12
+ import { createSignal } from './compat.js';
13
+ const SuspenseContext = createContext();
14
+ // Wire the runtime effect's suspend path to the nearest boundary. Registered once.
15
+ setSuspendHandler((promise, owner) => {
16
+ const boundary = readContextFrom(owner, SuspenseContext);
17
+ if (!boundary)
18
+ return; // no boundary above -> let it stay pending (no crash)
19
+ boundary.increment();
20
+ promise.finally(() => boundary.decrement());
21
+ });
22
+ /** Create a boundary's reactive state (pending counter + inFallback). */
23
+ export function createSuspenseBoundary() {
24
+ const [pending, setPending] = createSignal(0);
25
+ let count = 0;
26
+ return {
27
+ increment: () => setPending((count += 1)),
28
+ decrement: () => setPending((count -= 1)),
29
+ inFallback: () => pending() > 0,
30
+ };
31
+ }
32
+ /** Run `fn` (the boundary's children) under a Suspense scope, so suspended reads inside report to `boundary`. */
33
+ export function provideSuspense(boundary, fn) {
34
+ return provide(SuspenseContext, boundary, fn);
35
+ }
36
+ export { SuspenseContext };
@@ -0,0 +1,290 @@
1
+ // src/version.generated.ts
2
+ var VERSION = "1.0.0-alpha.100";
3
+
4
+ // src/lib/signal/graph/state.ts
5
+ var MAJOR = VERSION.split(".")[0];
6
+ var KEY = `__fluixi_signal_state_v${MAJOR}__`;
7
+ var VERSIONS_KEY = `__fluixi_signal_builds_v${MAJOR}__`;
8
+ var defaultSchedule = (run) => {
9
+ if (typeof queueMicrotask === "function") queueMicrotask(run);
10
+ else void Promise.resolve().then(run);
11
+ };
12
+ function defaults() {
13
+ return {
14
+ consumer: null,
15
+ untracked: false,
16
+ owner: null,
17
+ queue: [],
18
+ scheduled: false,
19
+ flushing: false,
20
+ batchDepth: 0,
21
+ hostSchedule: defaultSchedule,
22
+ onSuspend: null,
23
+ onError: null,
24
+ observer: null
25
+ };
26
+ }
27
+ var realm = globalThis;
28
+ function backfillState(existing) {
29
+ const fresh = defaults();
30
+ const target = existing;
31
+ for (const field of Object.keys(fresh)) {
32
+ if (!(field in existing)) target[field] = fresh[field];
33
+ }
34
+ return existing;
35
+ }
36
+ function claim() {
37
+ const existing = realm[KEY];
38
+ return existing ? backfillState(existing) : realm[KEY] = defaults();
39
+ }
40
+ var G = claim();
41
+ (realm[VERSIONS_KEY] ??= []).push(VERSION);
42
+
43
+ // src/lib/signal/graph/observe.ts
44
+ function observeReactiveNodes(next) {
45
+ G.observer = next;
46
+ return () => {
47
+ if (G.observer === next) G.observer = null;
48
+ };
49
+ }
50
+ var running = [];
51
+ var origin;
52
+ var currentScope;
53
+ function reportReactiveNode(report) {
54
+ const observer = G.observer;
55
+ if (observer) {
56
+ observer.created(
57
+ report.parents === void 0 ? { ...report, parents: running, origin: report.origin ?? origin, scope: report.scope ?? currentScope } : { ...report, scope: report.scope ?? currentScope }
58
+ );
59
+ }
60
+ }
61
+ function reportReactiveWrite(node, by) {
62
+ G.observer?.wrote?.(node, by);
63
+ }
64
+ function reportReactiveContextCreated(id) {
65
+ G.observer?.contextCreated?.(id);
66
+ }
67
+ function reportReactiveContext(id, kind, value) {
68
+ const observer = G.observer;
69
+ if (!observer?.context || !running.length) return;
70
+ observer.context(running[running.length - 1], id, kind, value);
71
+ }
72
+ function reportReactiveDispose(node) {
73
+ G.observer?.disposed?.(node);
74
+ }
75
+ var HOOK = "__FLUIXI_DEVTOOLS_HOOK__";
76
+ var hook = globalThis[HOOK];
77
+ if (typeof hook?.inject === "function") {
78
+ try {
79
+ hook.inject({ observeReactiveNodes, version: VERSION });
80
+ } catch {
81
+ }
82
+ }
83
+ function isObserved() {
84
+ return G.observer != null;
85
+ }
86
+
87
+ // src/lib/signal/graph/core.ts
88
+ var DIRTY = 2;
89
+ var Source = class {
90
+ constructor() {
91
+ /** Computeds, and watched leaves, that read this node. */
92
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
93
+ this.observers = null;
94
+ /** Watchers eagerly observing this node, which is how `runtime.ts` schedules effects. */
95
+ this.watchers = null;
96
+ /** Bumped whenever this node's value actually changes (equality-gated). */
97
+ this.version = 0;
98
+ }
99
+ /** Settle this node so a reader sees a current value/version. Overridden by Computed. */
100
+ updateIfNecessary() {
101
+ }
102
+ /** Link the current consumer (if any) as an observer of this node. */
103
+ track() {
104
+ if (G.untracked) return;
105
+ const consumer = G.consumer;
106
+ if (!consumer) return;
107
+ (this.observers ??= /* @__PURE__ */ new Set()).add(consumer);
108
+ (consumer.sources ??= /* @__PURE__ */ new Set()).add(this);
109
+ }
110
+ };
111
+ var State = class extends Source {
112
+ constructor(value, options) {
113
+ super();
114
+ this._value = value;
115
+ this._equals = options?.equals === false ? () => false : options?.equals ?? Object.is;
116
+ }
117
+ get() {
118
+ this.track();
119
+ return this._value;
120
+ }
121
+ set(next) {
122
+ if (this._equals(this._value, next)) return;
123
+ this._value = next;
124
+ this.version++;
125
+ reportReactiveWrite(this, G.consumer);
126
+ if (this.observers) for (const o of [...this.observers]) o.markDirty(DIRTY);
127
+ notifyWatchers(this);
128
+ }
129
+ /** Read without subscribing (peek). */
130
+ peek() {
131
+ return this._value;
132
+ }
133
+ };
134
+ function notifyWatchers(node) {
135
+ if (!node.watchers) return;
136
+ for (const w of [...node.watchers]) w._notify(node);
137
+ }
138
+
139
+ // src/lib/signal/graph/runtime.ts
140
+ function makeOwner(parent) {
141
+ return { cleanups: null, owned: null, parent, contexts: null };
142
+ }
143
+ function createContext(defaultValue, name) {
144
+ const id = Symbol(name ?? "context");
145
+ reportReactiveContextCreated(id);
146
+ const Provider = (props) => {
147
+ reportReactiveContext(id, "provide", props.value);
148
+ const parent = G.owner;
149
+ const owner = makeOwner(parent);
150
+ (owner.contexts = /* @__PURE__ */ new Map()).set(id, props.value);
151
+ if (parent) (parent.owned ??= []).push(owner);
152
+ G.owner = owner;
153
+ try {
154
+ return props.children;
155
+ } finally {
156
+ G.owner = parent;
157
+ }
158
+ };
159
+ return { id, defaultValue, Provider };
160
+ }
161
+ function readContextFrom(owner, context) {
162
+ let o = owner;
163
+ while (o) {
164
+ if (o.contexts && o.contexts.has(context.id)) return o.contexts.get(context.id);
165
+ o = o.parent;
166
+ }
167
+ return context.defaultValue;
168
+ }
169
+ function provide(context, value, fn) {
170
+ const owner = makeOwner(G.owner);
171
+ (owner.contexts = /* @__PURE__ */ new Map()).set(context.id, value);
172
+ if (G.owner) (G.owner.owned ??= []).push(owner);
173
+ const prev = G.owner;
174
+ G.owner = owner;
175
+ try {
176
+ return fn();
177
+ } finally {
178
+ G.owner = prev;
179
+ }
180
+ }
181
+ function setSuspendHandler(fn) {
182
+ G.onSuspend = fn;
183
+ }
184
+ function onCleanup(fn) {
185
+ if (!G.owner) return;
186
+ if (G.owner.disposed) {
187
+ fn();
188
+ return;
189
+ }
190
+ (G.owner.cleanups ??= []).push(fn);
191
+ }
192
+ function setScheduler(fn) {
193
+ G.hostSchedule = fn ?? ((run) => void Promise.resolve().then(run));
194
+ }
195
+ function flushSync() {
196
+ G.scheduled = false;
197
+ if (G.flushing) return;
198
+ G.flushing = true;
199
+ let guard = 0;
200
+ let failed = false;
201
+ let first;
202
+ try {
203
+ while (G.queue.length) {
204
+ if (++guard > 1e5) throw new Error("[fluixi] effect flush did not settle (cycle?)");
205
+ const batchOf = G.queue;
206
+ G.queue = [];
207
+ for (const e of batchOf) {
208
+ e.queued = false;
209
+ if (e.disposed) continue;
210
+ try {
211
+ e.run();
212
+ } catch (error) {
213
+ if (!failed) {
214
+ failed = true;
215
+ first = error;
216
+ }
217
+ }
218
+ }
219
+ }
220
+ } finally {
221
+ G.flushing = false;
222
+ }
223
+ if (failed) throw first;
224
+ }
225
+ function afterWrite() {
226
+ if (G.batchDepth === 0) flushSync();
227
+ }
228
+
229
+ // src/lib/signal/graph/compat.ts
230
+ setScheduler(() => {
231
+ });
232
+ var $SIGNAL = /* @__PURE__ */ Symbol.for("signal");
233
+ var $NODE = /* @__PURE__ */ Symbol.for("signal-node");
234
+ function createSignal(value, options) {
235
+ const state = new State(value, { equals: options?.equals });
236
+ const read = (() => state.get());
237
+ const write = ((next) => {
238
+ const v = typeof next === "function" ? next(state.peek()) : next;
239
+ state.set(v);
240
+ afterWrite();
241
+ return v;
242
+ });
243
+ Object.defineProperty(read, $SIGNAL, { value: true, enumerable: true });
244
+ Object.defineProperty(read, $NODE, {
245
+ value: {
246
+ get value() {
247
+ return state.peek();
248
+ },
249
+ get version() {
250
+ return state.version;
251
+ }
252
+ },
253
+ enumerable: false
254
+ });
255
+ reportReactiveNode({
256
+ kind: "signal",
257
+ node: state,
258
+ handle: read,
259
+ name: options?.name,
260
+ set: write
261
+ });
262
+ if (isObserved()) onCleanup(() => reportReactiveDispose(state));
263
+ return [read, write];
264
+ }
265
+
266
+ // src/lib/signal/graph/suspense.ts
267
+ var SuspenseContext = createContext();
268
+ setSuspendHandler((promise, owner) => {
269
+ const boundary = readContextFrom(owner, SuspenseContext);
270
+ if (!boundary) return;
271
+ boundary.increment();
272
+ promise.finally(() => boundary.decrement());
273
+ });
274
+ function createSuspenseBoundary() {
275
+ const [pending, setPending] = createSignal(0);
276
+ let count = 0;
277
+ return {
278
+ increment: () => setPending(count += 1),
279
+ decrement: () => setPending(count -= 1),
280
+ inFallback: () => pending() > 0
281
+ };
282
+ }
283
+ function provideSuspense(boundary, fn) {
284
+ return provide(SuspenseContext, boundary, fn);
285
+ }
286
+ export {
287
+ SuspenseContext,
288
+ createSuspenseBoundary,
289
+ provideSuspense
290
+ };