@getforma/core 1.0.6 → 1.0.8

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 (50) hide show
  1. package/README.md +4 -4
  2. package/dist/{chunk-V732ZBCU.cjs → chunk-7L3KHGEA.cjs} +95 -50
  3. package/dist/chunk-7L3KHGEA.cjs.map +1 -0
  4. package/dist/{chunk-VTPFK5TJ.js → chunk-7Q7LIV23.js} +59 -14
  5. package/dist/chunk-7Q7LIV23.js.map +1 -0
  6. package/dist/{chunk-DCTOXHPF.cjs → chunk-BARF67I6.cjs} +8 -8
  7. package/dist/chunk-BARF67I6.cjs.map +1 -0
  8. package/dist/{chunk-OZCHIVAZ.js → chunk-HLM5BZZQ.js} +2 -2
  9. package/dist/chunk-HLM5BZZQ.js.map +1 -0
  10. package/dist/{chunk-3U57L2TY.cjs → chunk-QLPCVK7C.cjs} +2 -2
  11. package/dist/chunk-QLPCVK7C.cjs.map +1 -0
  12. package/dist/{chunk-OUVOAYIO.js → chunk-TBWZZ3SI.js} +3 -3
  13. package/dist/chunk-TBWZZ3SI.js.map +1 -0
  14. package/dist/formajs-runtime-hardened.global.js.map +1 -1
  15. package/dist/formajs-runtime.global.js.map +1 -1
  16. package/dist/formajs.global.js +55 -10
  17. package/dist/formajs.global.js.map +1 -1
  18. package/dist/http.cjs +13 -13
  19. package/dist/http.cjs.map +1 -1
  20. package/dist/http.js +4 -4
  21. package/dist/http.js.map +1 -1
  22. package/dist/index.cjs +61 -61
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +141 -10
  25. package/dist/index.d.ts +141 -10
  26. package/dist/index.js +6 -6
  27. package/dist/index.js.map +1 -1
  28. package/dist/{resource-Cd0cGOxS.d.ts → resource-BHsgURy0.d.ts} +3 -1
  29. package/dist/{resource-DK98lW5e.d.cts → resource-DeEzxUz6.d.cts} +3 -1
  30. package/dist/runtime-hardened.cjs.map +1 -1
  31. package/dist/runtime-hardened.js.map +1 -1
  32. package/dist/runtime.cjs +29 -29
  33. package/dist/runtime.js +3 -3
  34. package/dist/server.cjs +7 -7
  35. package/dist/server.d.cts +2 -2
  36. package/dist/server.d.ts +2 -2
  37. package/dist/server.js +2 -2
  38. package/dist/{signal-YlS1kgfh.d.cts → signal-C9v4akyJ.d.cts} +2 -0
  39. package/dist/{signal-YlS1kgfh.d.ts → signal-C9v4akyJ.d.ts} +2 -0
  40. package/dist/tc39-compat.cjs +3 -3
  41. package/dist/tc39-compat.d.cts +1 -1
  42. package/dist/tc39-compat.d.ts +1 -1
  43. package/dist/tc39-compat.js +1 -1
  44. package/package.json +1 -1
  45. package/dist/chunk-3U57L2TY.cjs.map +0 -1
  46. package/dist/chunk-DCTOXHPF.cjs.map +0 -1
  47. package/dist/chunk-OUVOAYIO.js.map +0 -1
  48. package/dist/chunk-OZCHIVAZ.js.map +0 -1
  49. package/dist/chunk-V732ZBCU.cjs.map +0 -1
  50. package/dist/chunk-VTPFK5TJ.js.map +0 -1
package/dist/runtime.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunkV732ZBCU_cjs = require('./chunk-V732ZBCU.cjs');
4
- var chunkDCTOXHPF_cjs = require('./chunk-DCTOXHPF.cjs');
5
- var chunk3U57L2TY_cjs = require('./chunk-3U57L2TY.cjs');
3
+ var chunk7L3KHGEA_cjs = require('./chunk-7L3KHGEA.cjs');
4
+ var chunkBARF67I6_cjs = require('./chunk-BARF67I6.cjs');
5
+ var chunkQLPCVK7C_cjs = require('./chunk-QLPCVK7C.cjs');
6
6
 
7
7
  // src/dom/reconcile.ts
8
8
  function getBindTargets(el) {
@@ -968,7 +968,7 @@ function parseIfHandler(expr, scope) {
968
968
  }
969
969
  if (rest.length > 0) return null;
970
970
  return (e) => {
971
- chunkDCTOXHPF_cjs.batch(() => {
971
+ chunkBARF67I6_cjs.batch(() => {
972
972
  if (condExpr()) thenHandler(e);
973
973
  else elseHandler?.(e);
974
974
  });
@@ -1717,7 +1717,7 @@ function parseHandler(expr, scope) {
1717
1717
  const handlers = stmts.map((s) => parseHandler(s, scope));
1718
1718
  if (handlers.every((h) => h !== null)) {
1719
1719
  return (e) => {
1720
- chunkDCTOXHPF_cjs.batch(() => {
1720
+ chunkBARF67I6_cjs.batch(() => {
1721
1721
  for (const h of handlers) h(e);
1722
1722
  });
1723
1723
  };
@@ -1730,7 +1730,7 @@ function parseHandler(expr, scope) {
1730
1730
  const name = incrMatch[1];
1731
1731
  const op = incrMatch[2];
1732
1732
  return () => {
1733
- chunkDCTOXHPF_cjs.batch(() => {
1733
+ chunkBARF67I6_cjs.batch(() => {
1734
1734
  const val = scope.getters[name]?.() ?? 0;
1735
1735
  scope.setters[name]?.(op === "++" ? val + 1 : val - 1);
1736
1736
  });
@@ -1741,7 +1741,7 @@ function parseHandler(expr, scope) {
1741
1741
  const op = preIncrMatch[1];
1742
1742
  const name = preIncrMatch[2];
1743
1743
  return () => {
1744
- chunkDCTOXHPF_cjs.batch(() => {
1744
+ chunkBARF67I6_cjs.batch(() => {
1745
1745
  const val = scope.getters[name]?.() ?? 0;
1746
1746
  scope.setters[name]?.(op === "++" ? val + 1 : val - 1);
1747
1747
  });
@@ -1751,7 +1751,7 @@ function parseHandler(expr, scope) {
1751
1751
  if (toggleMatch && toggleMatch[1] === toggleMatch[2]) {
1752
1752
  const name = toggleMatch[1];
1753
1753
  return () => {
1754
- chunkDCTOXHPF_cjs.batch(() => {
1754
+ chunkBARF67I6_cjs.batch(() => {
1755
1755
  scope.setters[name]?.(!scope.getters[name]?.());
1756
1756
  });
1757
1757
  };
@@ -1763,7 +1763,7 @@ function parseHandler(expr, scope) {
1763
1763
  if (valExpr) {
1764
1764
  if (_debug) dbg(`parseHandler: assignment "${name} = ..." \u2014 setter exists:`, !!scope.setters[name], ", getter exists:", !!scope.getters[name]);
1765
1765
  return () => {
1766
- chunkDCTOXHPF_cjs.batch(() => {
1766
+ chunkBARF67I6_cjs.batch(() => {
1767
1767
  const val = valExpr();
1768
1768
  if (_debug) dbg(`SETTER: ${name} = ${val} (was: ${scope.getters[name]?.()})`);
1769
1769
  scope.setters[name]?.(val);
@@ -1778,7 +1778,7 @@ function parseHandler(expr, scope) {
1778
1778
  const valExpr = parseExpression(compoundMatch[3].trim(), scope);
1779
1779
  if (valExpr) {
1780
1780
  return () => {
1781
- chunkDCTOXHPF_cjs.batch(() => {
1781
+ chunkBARF67I6_cjs.batch(() => {
1782
1782
  const current = scope.getters[name]?.() ?? 0;
1783
1783
  const val = valExpr();
1784
1784
  switch (op) {
@@ -1859,7 +1859,7 @@ function buildHandler(expr, scope) {
1859
1859
  }
1860
1860
  });
1861
1861
  const unsafeHandler = (e) => {
1862
- chunkDCTOXHPF_cjs.batch(() => fn(proxy, e, e));
1862
+ chunkBARF67I6_cjs.batch(() => fn(proxy, e, e));
1863
1863
  };
1864
1864
  const result = {
1865
1865
  handler: unsafeHandler,
@@ -1907,7 +1907,7 @@ function initScope(stateEl) {
1907
1907
  const getters = {};
1908
1908
  const setters = {};
1909
1909
  for (const [key, initial] of Object.entries(state)) {
1910
- const [get, set] = chunk3U57L2TY_cjs.createSignal(initial);
1910
+ const [get, set] = chunkQLPCVK7C_cjs.createSignal(initial);
1911
1911
  getters[key] = get;
1912
1912
  setters[key] = set;
1913
1913
  }
@@ -2019,7 +2019,7 @@ function bindElement(el, scope, disposers) {
2019
2019
  const prevGetter = scope.getters[name];
2020
2020
  delete scope.getters[name];
2021
2021
  const evaluate = buildEvaluator(`{${expr}}`, scope);
2022
- const getter = chunk3U57L2TY_cjs.createComputed(evaluate);
2022
+ const getter = chunkQLPCVK7C_cjs.createComputed(evaluate);
2023
2023
  scope.getters[name] = getter;
2024
2024
  if (!prevGetter) {
2025
2025
  delete scope.setters[name];
@@ -2030,7 +2030,7 @@ function bindElement(el, scope, disposers) {
2030
2030
  const textExpr = !known || known.has("data-text") ? el.getAttribute("data-text") : null;
2031
2031
  if (textExpr) {
2032
2032
  const evaluate = buildEvaluator(textExpr, scope);
2033
- const dispose = chunkDCTOXHPF_cjs.internalEffect(() => {
2033
+ const dispose = chunkBARF67I6_cjs.internalEffect(() => {
2034
2034
  setElementTextFast(el, toTextValue(evaluate()));
2035
2035
  });
2036
2036
  disposers.push(dispose);
@@ -2045,7 +2045,7 @@ function bindElement(el, scope, disposers) {
2045
2045
  dbg(`bindElement: data-show="${showExpr}" on <${tag}${cls}>`);
2046
2046
  }
2047
2047
  let initialized = false;
2048
- const dispose = chunkDCTOXHPF_cjs.internalEffect(() => {
2048
+ const dispose = chunkBARF67I6_cjs.internalEffect(() => {
2049
2049
  const visible = !!evaluate();
2050
2050
  if (_debug) dbg(`data-show effect: "${showExpr}" \u2192 ${visible}`);
2051
2051
  applyShowVisibility(el, visible, transition, !initialized);
@@ -2064,7 +2064,7 @@ function bindElement(el, scope, disposers) {
2064
2064
  const parent = el.parentNode;
2065
2065
  let inserted = true;
2066
2066
  let initialized = false;
2067
- const dispose = chunkDCTOXHPF_cjs.internalEffect(() => {
2067
+ const dispose = chunkBARF67I6_cjs.internalEffect(() => {
2068
2068
  const show = !!evaluate();
2069
2069
  if (show && !inserted) {
2070
2070
  clearTransitionState(el);
@@ -2103,7 +2103,7 @@ function bindElement(el, scope, disposers) {
2103
2103
  const setter = scope.setters[prop];
2104
2104
  if (getter && setter) {
2105
2105
  const input = el;
2106
- const dispose = chunkDCTOXHPF_cjs.internalEffect(() => {
2106
+ const dispose = chunkBARF67I6_cjs.internalEffect(() => {
2107
2107
  const val = getter();
2108
2108
  if (input.type === "checkbox") {
2109
2109
  input.checked = !!val;
@@ -2167,14 +2167,14 @@ function bindElement(el, scope, disposers) {
2167
2167
  } else if (name.startsWith("data-class:")) {
2168
2168
  const cls = name.slice(11);
2169
2169
  const evaluate = buildEvaluator(attr.value, scope);
2170
- const dispose = chunkDCTOXHPF_cjs.internalEffect(() => {
2170
+ const dispose = chunkBARF67I6_cjs.internalEffect(() => {
2171
2171
  el.classList.toggle(cls, !!evaluate());
2172
2172
  });
2173
2173
  disposers.push(dispose);
2174
2174
  } else if (name.startsWith("data-bind:")) {
2175
2175
  const attrName = name.slice(10);
2176
2176
  const evaluate = buildEvaluator(attr.value, scope);
2177
- const dispose = chunkDCTOXHPF_cjs.internalEffect(() => {
2177
+ const dispose = chunkBARF67I6_cjs.internalEffect(() => {
2178
2178
  const val = evaluate();
2179
2179
  if (val == null || val === false) {
2180
2180
  el.removeAttribute(attrName);
@@ -2197,7 +2197,7 @@ function bindElement(el, scope, disposers) {
2197
2197
  if (saved !== null) setter(JSON.parse(saved));
2198
2198
  } catch {
2199
2199
  }
2200
- const dispose = chunkDCTOXHPF_cjs.internalEffect(() => {
2200
+ const dispose = chunkBARF67I6_cjs.internalEffect(() => {
2201
2201
  try {
2202
2202
  localStorage.setItem(key, JSON.stringify(getter()));
2203
2203
  } catch {
@@ -2284,7 +2284,7 @@ function bindElement(el, scope, disposers) {
2284
2284
  });
2285
2285
  }
2286
2286
  } : void 0;
2287
- const dispose = chunkDCTOXHPF_cjs.internalEffect(() => {
2287
+ const dispose = chunkBARF67I6_cjs.internalEffect(() => {
2288
2288
  const rawItems = evaluate();
2289
2289
  if (!Array.isArray(rawItems)) {
2290
2290
  for (const n of oldNodes) {
@@ -2305,7 +2305,7 @@ function bindElement(el, scope, disposers) {
2305
2305
  }
2306
2306
  const prevNodes = new Set(oldNodes);
2307
2307
  if (keyProp) {
2308
- const result = chunkV732ZBCU_cjs.reconcileList(
2308
+ const result = chunk7L3KHGEA_cjs.reconcileList(
2309
2309
  el,
2310
2310
  oldItems,
2311
2311
  rawItems,
@@ -2335,7 +2335,7 @@ function bindElement(el, scope, disposers) {
2335
2335
  } else {
2336
2336
  const wrapped = rawItems.map((item, i) => ({ __idx: i, __item: item }));
2337
2337
  const oldWrapped = oldItems;
2338
- const result = chunkV732ZBCU_cjs.reconcileList(
2338
+ const result = chunk7L3KHGEA_cjs.reconcileList(
2339
2339
  el,
2340
2340
  oldWrapped,
2341
2341
  wrapped,
@@ -2384,16 +2384,16 @@ function bindElement(el, scope, disposers) {
2384
2384
  else if (k === "error") errorTarget = v;
2385
2385
  else if (k === "poll") interval = parseInt(v ?? "0", 10);
2386
2386
  }
2387
- const [getTarget, setTarget] = chunk3U57L2TY_cjs.createSignal(null);
2387
+ const [getTarget, setTarget] = chunkQLPCVK7C_cjs.createSignal(null);
2388
2388
  scope.getters[target] = getTarget;
2389
2389
  scope.setters[target] = setTarget;
2390
2390
  if (loadingTarget) {
2391
- const [gl, sl] = chunk3U57L2TY_cjs.createSignal(false);
2391
+ const [gl, sl] = chunkQLPCVK7C_cjs.createSignal(false);
2392
2392
  scope.getters[loadingTarget] = gl;
2393
2393
  scope.setters[loadingTarget] = sl;
2394
2394
  }
2395
2395
  if (errorTarget) {
2396
- const [ge, se] = chunk3U57L2TY_cjs.createSignal(null);
2396
+ const [ge, se] = chunkQLPCVK7C_cjs.createSignal(null);
2397
2397
  scope.getters[errorTarget] = ge;
2398
2398
  scope.setters[errorTarget] = se;
2399
2399
  }
@@ -2722,7 +2722,7 @@ function getScopes() {
2722
2722
  function setScopeValue(element, key, value) {
2723
2723
  const scope = element.__formaScope;
2724
2724
  if (!scope?.setters[key]) return;
2725
- chunkDCTOXHPF_cjs.batch(() => {
2725
+ chunkBARF67I6_cjs.batch(() => {
2726
2726
  scope.setters[key](value);
2727
2727
  });
2728
2728
  }
@@ -2731,7 +2731,7 @@ function resetScope(element) {
2731
2731
  const initialJSON = element.__formaInitialState;
2732
2732
  if (!scope || !initialJSON) return;
2733
2733
  const initial = parseState(initialJSON);
2734
- chunkDCTOXHPF_cjs.batch(() => {
2734
+ chunkBARF67I6_cjs.batch(() => {
2735
2735
  for (const [key, val] of Object.entries(initial)) {
2736
2736
  scope.setters[key]?.(val);
2737
2737
  }
@@ -2761,7 +2761,7 @@ function getReconciler() {
2761
2761
  }
2762
2762
  }
2763
2763
  },
2764
- batch: chunkDCTOXHPF_cjs.batch
2764
+ batch: chunkBARF67I6_cjs.batch
2765
2765
  });
2766
2766
  }
2767
2767
  return _reconciler;
package/dist/runtime.js CHANGED
@@ -1,6 +1,6 @@
1
- import { reconcileList } from './chunk-VTPFK5TJ.js';
2
- import { internalEffect, batch } from './chunk-OUVOAYIO.js';
3
- import { createSignal, createComputed } from './chunk-OZCHIVAZ.js';
1
+ import { reconcileList } from './chunk-7Q7LIV23.js';
2
+ import { internalEffect, batch } from './chunk-TBWZZ3SI.js';
3
+ import { createSignal, createComputed } from './chunk-HLM5BZZQ.js';
4
4
 
5
5
  // src/dom/reconcile.ts
6
6
  function getBindTargets(el) {
package/dist/server.cjs CHANGED
@@ -1,25 +1,25 @@
1
1
  'use strict';
2
2
 
3
- var chunkDCTOXHPF_cjs = require('./chunk-DCTOXHPF.cjs');
4
- var chunk3U57L2TY_cjs = require('./chunk-3U57L2TY.cjs');
3
+ var chunkBARF67I6_cjs = require('./chunk-BARF67I6.cjs');
4
+ var chunkQLPCVK7C_cjs = require('./chunk-QLPCVK7C.cjs');
5
5
 
6
6
  // src/server/action.ts
7
7
  function createAction(serverFn, options) {
8
- const [pending, setPending] = chunk3U57L2TY_cjs.createSignal(false);
9
- const [error, setError] = chunk3U57L2TY_cjs.createSignal(void 0);
8
+ const [pending, setPending] = chunkQLPCVK7C_cjs.createSignal(false);
9
+ const [error, setError] = chunkQLPCVK7C_cjs.createSignal(void 0);
10
10
  const action = async (...args) => {
11
11
  setPending(true);
12
12
  setError(void 0);
13
13
  if (options?.optimistic) {
14
14
  try {
15
- chunkDCTOXHPF_cjs.batch(() => options.optimistic(...args));
15
+ chunkBARF67I6_cjs.batch(() => options.optimistic(...args));
16
16
  } catch {
17
17
  }
18
18
  }
19
19
  try {
20
20
  const result = await serverFn(...args);
21
21
  if (options?.onSuccess) {
22
- chunkDCTOXHPF_cjs.batch(() => options.onSuccess(result, ...args));
22
+ chunkBARF67I6_cjs.batch(() => options.onSuccess(result, ...args));
23
23
  }
24
24
  if (options?.invalidates) {
25
25
  for (const resource of options.invalidates) {
@@ -31,7 +31,7 @@ function createAction(serverFn, options) {
31
31
  } catch (err) {
32
32
  if (options?.onError) {
33
33
  try {
34
- chunkDCTOXHPF_cjs.batch(() => options.onError(err, ...args));
34
+ chunkBARF67I6_cjs.batch(() => options.onError(err, ...args));
35
35
  } catch {
36
36
  }
37
37
  }
package/dist/server.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as Resource } from './resource-DK98lW5e.cjs';
2
- import './signal-YlS1kgfh.cjs';
1
+ import { R as Resource } from './resource-DeEzxUz6.cjs';
2
+ import './signal-C9v4akyJ.cjs';
3
3
 
4
4
  /**
5
5
  * FormaJS Server - Action
package/dist/server.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as Resource } from './resource-Cd0cGOxS.js';
2
- import './signal-YlS1kgfh.js';
1
+ import { R as Resource } from './resource-BHsgURy0.js';
2
+ import './signal-C9v4akyJ.js';
3
3
 
4
4
  /**
5
5
  * FormaJS Server - Action
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
- import { batch } from './chunk-OUVOAYIO.js';
2
- import { createSignal } from './chunk-OZCHIVAZ.js';
1
+ import { batch } from './chunk-TBWZZ3SI.js';
2
+ import { createSignal } from './chunk-HLM5BZZQ.js';
3
3
 
4
4
  // src/server/action.ts
5
5
  function createAction(serverFn, options) {
@@ -6,7 +6,9 @@
6
6
  *
7
7
  * TC39 Signals equivalent: Signal.State
8
8
  */
9
+ /** A function that reads the current value of a signal. */
9
10
  type SignalGetter<T> = () => T;
11
+ /** A function that updates a signal — accepts a value or an updater function. */
10
12
  type SignalSetter<T> = (v: T | ((prev: T) => T)) => void;
11
13
  interface SignalOptions<T> {
12
14
  /** Debug name — attached to getter in dev mode for devtools inspection. */
@@ -6,7 +6,9 @@
6
6
  *
7
7
  * TC39 Signals equivalent: Signal.State
8
8
  */
9
+ /** A function that reads the current value of a signal. */
9
10
  type SignalGetter<T> = () => T;
11
+ /** A function that updates a signal — accepts a value or an updater function. */
10
12
  type SignalSetter<T> = (v: T | ((prev: T) => T)) => void;
11
13
  interface SignalOptions<T> {
12
14
  /** Debug name — attached to getter in dev mode for devtools inspection. */
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var chunk3U57L2TY_cjs = require('./chunk-3U57L2TY.cjs');
3
+ var chunkQLPCVK7C_cjs = require('./chunk-QLPCVK7C.cjs');
4
4
 
5
5
  // src/reactive/tc39-compat.ts
6
6
  var State = class {
7
7
  _get;
8
8
  _set;
9
9
  constructor(initialValue, options) {
10
- const [getter, setter] = chunk3U57L2TY_cjs.createSignal(initialValue, options);
10
+ const [getter, setter] = chunkQLPCVK7C_cjs.createSignal(initialValue, options);
11
11
  this._get = getter;
12
12
  this._set = setter;
13
13
  if (options?.name) {
@@ -24,7 +24,7 @@ var State = class {
24
24
  var Computed = class {
25
25
  _get;
26
26
  constructor(fn) {
27
- this._get = chunk3U57L2TY_cjs.createComputed(fn);
27
+ this._get = chunkQLPCVK7C_cjs.createComputed(fn);
28
28
  }
29
29
  get() {
30
30
  return this._get();
@@ -1,4 +1,4 @@
1
- import { a as SignalOptions } from './signal-YlS1kgfh.cjs';
1
+ import { a as SignalOptions } from './signal-C9v4akyJ.cjs';
2
2
 
3
3
  /**
4
4
  * Forma Reactive - TC39 Signals Compatibility Layer
@@ -1,4 +1,4 @@
1
- import { a as SignalOptions } from './signal-YlS1kgfh.js';
1
+ import { a as SignalOptions } from './signal-C9v4akyJ.js';
2
2
 
3
3
  /**
4
4
  * Forma Reactive - TC39 Signals Compatibility Layer
@@ -1,4 +1,4 @@
1
- import { createSignal, createComputed } from './chunk-OZCHIVAZ.js';
1
+ import { createSignal, createComputed } from './chunk-HLM5BZZQ.js';
2
2
 
3
3
  // src/reactive/tc39-compat.ts
4
4
  var State = class {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@getforma/core",
3
3
  "author": "Forma <victor@getforma.dev>",
4
- "version": "1.0.6",
4
+ "version": "1.0.8",
5
5
  "description": "Real DOM reactive library — fine-grained signals, islands architecture, SSR hydration. No virtual DOM, no diffing. ~15KB gzipped.",
6
6
  "type": "module",
7
7
  "main": "./dist/index.cjs",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/reactive/signal.ts","../src/reactive/computed.ts"],"names":["prevSub","setActiveSub","prev","createRawSignal","rawComputed"],"mappings":";;;;;AAkEA,SAAS,cAAA,CACP,CAAA,EACA,CAAA,EACA,MAAA,EACM;AACN,EAAA,IAAI,OAAO,MAAM,UAAA,EAAY;AAC3B,IAAA,IAAI,MAAA,EAAQ;AAEV,MAAA,MAAMA,QAAAA,GAAUC,0BAAa,MAAS,CAAA;AACtC,MAAA,MAAMC,QAAO,CAAA,EAAE;AACf,MAAAD,yBAAA,CAAaD,QAAO,CAAA;AACpB,MAAA,IAAI,MAAA,CAAOE,KAAAA,EAAM,CAAC,CAAA,EAAG;AAAA,IACvB;AACA,IAAA,CAAA,CAAE,CAAC,CAAA;AACH,IAAA;AAAA,EACF;AAGA,EAAA,MAAM,OAAA,GAAUD,0BAAa,MAAS,CAAA;AACtC,EAAA,MAAM,OAAO,CAAA,EAAE;AACf,EAAAA,yBAAA,CAAa,OAAO,CAAA;AACpB,EAAA,MAAM,IAAA,GAAQ,EAAqB,IAAI,CAAA;AACvC,EAAA,IAAI,MAAA,IAAU,MAAA,CAAO,IAAA,EAAM,IAAI,CAAA,EAAG;AAClC,EAAA,CAAA,CAAE,IAAI,CAAA;AACR;AAqBO,SAAS,YAAA,CAAgB,cAAiB,OAAA,EAA0E;AACzH,EAAA,MAAM,CAAA,GAAIE,oBAAmB,YAAY,CAAA;AACzC,EAAA,MAAM,MAAA,GAAS,CAAA;AACf,EAAA,MAAM,KAAK,OAAA,EAAS,MAAA;AACpB,EAAA,MAAM,SAA0B,CAAC,CAAA,KAA4B,cAAA,CAAe,CAAA,EAAG,GAAG,EAAE,CAAA;AAEpF,EAAA,OAAO,CAAC,QAAQ,MAAM,CAAA;AACxB;AC7EO,SAAS,eAAkB,EAAA,EAAuC;AACvE,EAAA,OAAOC,sBAAY,EAAE,CAAA;AACvB","file":"chunk-3U57L2TY.cjs","sourcesContent":["/**\n * Forma Reactive - Signal\n *\n * Fine-grained reactive primitive backed by alien-signals.\n * API: createSignal returns [getter, setter] tuple following SolidJS conventions.\n *\n * TC39 Signals equivalent: Signal.State\n */\n\nimport { signal as createRawSignal, setActiveSub } from 'alien-signals';\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport type SignalGetter<T> = () => T;\nexport type SignalSetter<T> = (v: T | ((prev: T) => T)) => void;\n\nexport interface SignalOptions<T> {\n /** Debug name — attached to getter in dev mode for devtools inspection. */\n name?: string;\n /**\n * Custom equality check. When provided, the setter will read the current\n * value and only update the signal if `equals(prev, next)` returns `false`.\n *\n * Default: none (alien-signals uses strict inequality `!==` internally).\n *\n * ```ts\n * const [pos, setPos] = createSignal(\n * { x: 0, y: 0 },\n * { equals: (a, b) => a.x === b.x && a.y === b.y },\n * );\n *\n * setPos({ x: 0, y: 0 }); // skipped — equals returns true\n * setPos({ x: 1, y: 0 }); // applied — equals returns false\n * ```\n */\n equals?: (prev: T, next: T) => boolean;\n}\n\n/**\n * Wrap a value so the setter treats it as a literal value, not a functional updater.\n *\n * When `T` is itself a function type, passing a function to the setter is\n * ambiguous -- it looks like a functional update (`prev => next`). Use\n * `value()` to disambiguate:\n *\n * ```ts\n * const [getFn, setFn] = createSignal<() => void>(() => console.log('a'));\n *\n * // BUG: interpreted as a functional update -- calls the arrow with prev\n * // setFn(() => console.log('b'));\n *\n * // Correct: wraps in a thunk so the setter stores it as-is\n * setFn(value(() => console.log('b')));\n * ```\n */\nexport function value<T>(v: T): () => T {\n return () => v;\n}\n\ntype RawSignal<T> = {\n (): T;\n (value: T): void;\n};\n\nfunction applySignalSet<T>(\n s: RawSignal<T>,\n v: T | ((prev: T) => T),\n equals?: (prev: T, next: T) => boolean,\n): void {\n if (typeof v !== 'function') {\n if (equals) {\n // Read current value without tracking\n const prevSub = setActiveSub(undefined);\n const prev = s();\n setActiveSub(prevSub);\n if (equals(prev, v)) return; // skip — values are equal\n }\n s(v);\n return;\n }\n\n // Functional update: read prev without tracking\n const prevSub = setActiveSub(undefined);\n const prev = s();\n setActiveSub(prevSub);\n const next = (v as (prev: T) => T)(prev);\n if (equals && equals(prev, next)) return; // skip — values are equal\n s(next);\n}\n\n/**\n * Create a reactive signal.\n *\n * ```ts\n * const [count, setCount] = createSignal(0);\n * console.log(count()); // 0\n * setCount(1);\n * setCount(prev => prev + 1);\n * ```\n *\n * With custom equality:\n *\n * ```ts\n * const [pos, setPos] = createSignal(\n * { x: 0, y: 0 },\n * { equals: (a, b) => a.x === b.x && a.y === b.y },\n * );\n * ```\n */\nexport function createSignal<T>(initialValue: T, options?: SignalOptions<T>): [get: SignalGetter<T>, set: SignalSetter<T>] {\n const s = createRawSignal<T>(initialValue) as RawSignal<T>;\n const getter = s as unknown as SignalGetter<T>;\n const eq = options?.equals;\n const setter: SignalSetter<T> = (v: T | ((prev: T) => T)) => applySignalSet(s, v, eq);\n\n return [getter, setter];\n}\n","/**\n * Forma Reactive - Computed\n *\n * Lazy, cached derived value that participates in the reactive graph.\n * Backed by alien-signals for automatic dependency tracking\n * and cache invalidation.\n *\n * TC39 Signals equivalent: Signal.Computed\n */\n\nimport { computed as rawComputed } from 'alien-signals';\n\n/**\n * Create a lazy, cached computed value.\n *\n * Note: Unlike SolidJS's createComputed (which is an eager synchronous\n * side effect), this is a lazy cached derivation — equivalent to\n * SolidJS's createMemo. Both createComputed and createMemo in FormaJS\n * are identical.\n *\n * The getter receives the previous value as an argument, enabling\n * efficient diffing patterns without a separate signal:\n *\n * ```ts\n * const [count, setCount] = createSignal(0);\n * const doubled = createComputed(() => count() * 2);\n * console.log(doubled()); // 0\n * setCount(5);\n * console.log(doubled()); // 10\n * ```\n *\n * With previous value (for diffing):\n *\n * ```ts\n * const changes = createComputed((prev) => {\n * const next = items();\n * if (prev) console.log(`changed from ${prev.length} to ${next.length} items`);\n * return next;\n * });\n * ```\n */\nexport function createComputed<T>(fn: (previousValue?: T) => T): () => T {\n return rawComputed(fn);\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/reactive/root.ts","../src/reactive/cleanup.ts","../src/reactive/dev.ts","../src/reactive/effect.ts","../src/reactive/memo.ts","../src/reactive/batch.ts","../src/reactive/untrack.ts","../src/reactive/on.ts","../src/reactive/ref.ts","../src/reactive/reducer.ts","../src/reactive/suspense-context.ts","../src/reactive/resource.ts"],"names":["rawEffectScope","rawEffect","createComputed","startBatch","endBatch","setActiveSub","value","createSignal"],"mappings":"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","file":"chunk-DCTOXHPF.cjs","sourcesContent":["/**\n * Forma Reactive - Root\n *\n * Explicit reactive ownership scope. All effects created inside a root\n * are automatically disposed when the root is torn down.\n *\n * Uses alien-signals' `effectScope` under the hood for native graph-level\n * effect tracking, with a userland disposer list for non-effect cleanup\n * (e.g., event listeners, DOM references, timers).\n */\n\nimport { effectScope as rawEffectScope } from 'alien-signals';\n\n// ---------------------------------------------------------------------------\n// Root scope tracking\n// ---------------------------------------------------------------------------\n\nlet currentRoot: RootScope | null = null;\nconst rootStack: (RootScope | null)[] = [];\n\ninterface RootScope {\n /** Userland disposers (event listeners, DOM refs, timers, etc.) */\n disposers: (() => void)[];\n /** alien-signals effect scope dispose — tears down all reactive effects */\n scopeDispose: (() => void) | null;\n}\n\n/**\n * Create a reactive root scope.\n *\n * All effects created (via `createEffect`) inside the callback are tracked\n * at both the reactive graph level (via alien-signals effectScope) and the\n * userland level (via registerDisposer). The returned `dispose` function\n * tears down everything.\n *\n * ```ts\n * const dispose = createRoot(() => {\n * createEffect(() => console.log(count()));\n * createEffect(() => console.log(name()));\n * });\n * // later: dispose() stops both effects\n * ```\n */\nexport function createRoot<T>(fn: (dispose: () => void) => T): T {\n const scope: RootScope = { disposers: [], scopeDispose: null };\n\n rootStack.push(currentRoot);\n currentRoot = scope;\n\n const dispose = () => {\n // Dispose alien-signals effect scope first (reactive graph cleanup)\n if (scope.scopeDispose) {\n try { scope.scopeDispose(); } catch { /* ensure userland disposers still run */ }\n scope.scopeDispose = null;\n }\n // Then run userland disposers\n for (const d of scope.disposers) {\n try { d(); } catch { /* ensure all disposers run */ }\n }\n scope.disposers.length = 0;\n };\n\n let result: T;\n try {\n // Wrap in alien-signals effectScope for native effect tracking\n scope.scopeDispose = rawEffectScope(() => {\n result = fn(dispose);\n });\n } finally {\n currentRoot = rootStack.pop() ?? null;\n }\n\n return result!;\n}\n\n/**\n * @internal — called by createEffect to register disposers in the current root.\n */\nexport function registerDisposer(dispose: () => void): void {\n if (currentRoot) {\n currentRoot.disposers.push(dispose);\n }\n}\n\n/**\n * @internal — check if we're inside a root scope.\n */\nexport function hasActiveRoot(): boolean {\n return currentRoot !== null;\n}\n","/**\n * Forma Reactive - Cleanup\n *\n * Register cleanup functions within reactive scopes.\n * Inspired by SolidJS onCleanup().\n */\n\n// ---------------------------------------------------------------------------\n// Cleanup context tracking\n// ---------------------------------------------------------------------------\n\ntype CleanupCollector = ((fn: () => void) => void) | null;\n\nlet currentCleanupCollector: CleanupCollector = null;\n\n/**\n * Register a cleanup function in the current reactive scope.\n * The cleanup runs before the effect re-executes and on disposal.\n *\n * More composable than returning a cleanup from the effect function,\n * since it can be called from helper functions.\n *\n * ```ts\n * createEffect(() => {\n * const timer = setInterval(tick, 1000);\n * onCleanup(() => clearInterval(timer));\n * });\n * ```\n */\nexport function onCleanup(fn: () => void): void {\n currentCleanupCollector?.(fn);\n}\n\n/**\n * @internal — Set the cleanup collector for the current effect execution.\n */\nexport function setCleanupCollector(collector: CleanupCollector): CleanupCollector {\n const prev = currentCleanupCollector;\n currentCleanupCollector = collector;\n return prev;\n}\n","/**\n * Forma Reactive - Dev Mode\n *\n * Development utilities stripped from production builds via __DEV__ flag.\n * Bundlers replace __DEV__ with false → dead-code elimination removes all dev paths.\n */\n\n// __DEV__ is replaced by bundler (tsup define). Defaults to true for unbundled usage.\ndeclare const process: { env?: Record<string, string | undefined> } | undefined;\nexport const __DEV__: boolean = typeof process !== 'undefined'\n ? (process!.env?.NODE_ENV !== 'production')\n : true;\n\n// ---------------------------------------------------------------------------\n// Global error handler\n// ---------------------------------------------------------------------------\n\nexport type ErrorHandler = (error: unknown, info?: { source?: string }) => void;\n\nlet _errorHandler: ErrorHandler | null = null;\n\n/**\n * Install a global error handler for FormaJS reactive errors.\n * Called when effects, computeds, or event handlers throw.\n *\n * ```ts\n * onError((err, info) => {\n * console.error(`[${info?.source}]`, err);\n * Sentry.captureException(err);\n * });\n * ```\n */\nexport function onError(handler: ErrorHandler): void {\n _errorHandler = handler;\n}\n\n/** @internal */\nexport function reportError(error: unknown, source?: string): void {\n if (_errorHandler) {\n try { _errorHandler(error, source ? { source } : {}); } catch { /* prevent infinite loop */ }\n }\n if (__DEV__) {\n console.error(`[forma] ${source ?? 'Unknown'} error:`, error);\n }\n}\n","/**\n * Forma Reactive - Effect\n *\n * Side-effectful reactive computation that auto-tracks signal dependencies.\n * Backed by alien-signals for automatic dependency tracking.\n *\n * TC39 Signals equivalent: Signal.subtle.Watcher (effect is a userland concept)\n */\n\nimport { effect as rawEffect } from 'alien-signals';\nimport { hasActiveRoot, registerDisposer } from './root.js';\nimport { setCleanupCollector } from './cleanup.js';\nimport { reportError } from './dev.js';\n\n// ---------------------------------------------------------------------------\n// Cleanup array pool — avoids allocating a new array every effect re-run\n// ---------------------------------------------------------------------------\n\nconst POOL_SIZE = 32;\nconst MAX_REENTRANT_RUNS = 100;\nconst pool: (() => void)[][] = [];\nfor (let i = 0; i < POOL_SIZE; i++) pool.push([]);\nlet poolIdx = POOL_SIZE;\n\nfunction acquireArray(): (() => void)[] {\n if (poolIdx > 0) {\n const arr = pool[--poolIdx]!;\n arr.length = 0;\n return arr;\n }\n return [];\n}\n\nfunction releaseArray(arr: (() => void)[]): void {\n arr.length = 0;\n if (poolIdx < POOL_SIZE) {\n pool[poolIdx++] = arr;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Unified cleanup runner — single function for both re-run and dispose paths\n// ---------------------------------------------------------------------------\n\nfunction runCleanup(fn: (() => void) | undefined): void {\n if (fn === undefined) return;\n try {\n fn();\n } catch (e) {\n reportError(e, 'effect cleanup');\n }\n}\n\nfunction runCleanups(bag: (() => void)[] | undefined): void {\n if (bag === undefined) return;\n for (let i = 0; i < bag.length; i++) {\n try { bag[i]!(); } catch (e) { reportError(e, 'effect cleanup'); }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a reactive effect that auto-tracks signal dependencies.\n *\n * The provided function runs immediately and re-runs whenever any signal it\n * reads changes. If the function returns a cleanup function, that cleanup is\n * called before each re-run and on disposal.\n *\n * Additionally, `onCleanup()` can be called inside the effect to register\n * cleanup functions composably.\n *\n * Returns a dispose function that stops the effect.\n */\n/**\n * @internal — Lightweight effect for Forma's internal DOM bindings.\n *\n * Bypasses createEffect's cleanup infrastructure (pool, collector, error\n * reporting, engine compression) since internal effects never use\n * onCleanup() or return cleanup functions. This saves ~4 function calls\n * per effect creation and per re-run.\n *\n * ONLY use for effects that:\n * 1. Never call onCleanup()\n * 2. Never return a cleanup function\n * 3. Contain simple \"read signal → write DOM\" logic\n */\nexport function internalEffect(fn: () => void): () => void {\n const dispose = rawEffect(fn);\n if (hasActiveRoot()) {\n registerDisposer(dispose);\n }\n return dispose;\n}\n\nexport function createEffect(fn: () => void | (() => void)): () => void {\n const shouldRegister = hasActiveRoot();\n\n // Most effects have zero or one cleanup. Track the single-cleanup case\n // without array allocation; only promote to pooled array when needed.\n let cleanup: (() => void) | undefined;\n let cleanupBag: (() => void)[] | undefined;\n let nextCleanup: (() => void) | undefined;\n let nextCleanupBag: (() => void)[] | undefined;\n\n const addCleanup = (cb: () => void) => {\n if (nextCleanupBag !== undefined) {\n nextCleanupBag.push(cb);\n return;\n }\n if (nextCleanup !== undefined) {\n const bag = acquireArray();\n bag.push(nextCleanup, cb);\n nextCleanup = undefined;\n nextCleanupBag = bag;\n return;\n }\n nextCleanup = cb;\n };\n\n // \"Engine Compression\" exploit: most effects never use cleanup (onCleanup()\n // or return value). After the first clean run, we know this effect is\n // \"cleanup-free\" and can skip the entire cleanup infrastructure on re-runs.\n // This saves 4 function calls per re-run: acquireArray, setCleanupCollector,\n // releaseArray, and bag inspection. Like the engine compression ratio exploit —\n // the \"rules\" say we should always prepare for cleanup, but we measure at\n // \"room temperature\" (first run) and exploit the gap.\n let skipCleanupInfra = false;\n let firstRun = true;\n let running = false;\n let rerunRequested = false;\n\n const runOnce = () => {\n // Run and clear previous cleanups (only if any exist).\n if (cleanup !== undefined) {\n runCleanup(cleanup);\n cleanup = undefined;\n }\n if (cleanupBag !== undefined) {\n runCleanups(cleanupBag);\n releaseArray(cleanupBag);\n cleanupBag = undefined;\n }\n\n // Ultra-fast path: this effect has proven it doesn't use cleanup.\n // Skip acquireArray + setCleanupCollector + bag checks + releaseArray.\n if (skipCleanupInfra) {\n try { fn(); } catch (e) { reportError(e, 'effect'); }\n return;\n }\n\n nextCleanup = undefined;\n nextCleanupBag = undefined;\n\n // Full path: install collector for onCleanup() calls.\n const prevCollector = setCleanupCollector(addCleanup);\n\n try {\n const result = fn();\n\n if (typeof result === 'function') {\n addCleanup(result as () => void);\n }\n\n // Hot path: no cleanups registered or returned — enable ultra-fast path.\n if (nextCleanup === undefined && nextCleanupBag === undefined) {\n // First clean run → enable ultra-fast path for all subsequent runs\n if (firstRun) skipCleanupInfra = true;\n return;\n }\n\n if (nextCleanupBag !== undefined) {\n cleanupBag = nextCleanupBag;\n } else {\n cleanup = nextCleanup;\n }\n } catch (e) {\n reportError(e, 'effect');\n\n if (nextCleanupBag !== undefined) {\n cleanupBag = nextCleanupBag;\n } else {\n cleanup = nextCleanup;\n }\n } finally {\n setCleanupCollector(prevCollector);\n firstRun = false;\n }\n };\n\n const safeFn = () => {\n if (running) {\n rerunRequested = true;\n return;\n }\n\n running = true;\n try {\n let reentrantRuns = 0;\n do {\n rerunRequested = false;\n runOnce();\n if (rerunRequested) {\n reentrantRuns++;\n if (reentrantRuns >= MAX_REENTRANT_RUNS) {\n reportError(\n new Error(`createEffect exceeded ${MAX_REENTRANT_RUNS} re-entrant runs`),\n 'effect',\n );\n rerunRequested = false;\n }\n }\n } while (rerunRequested);\n } finally {\n running = false;\n }\n };\n\n const dispose = rawEffect(safeFn);\n\n // Wrap dispose to also run final cleanups\n let disposed = false;\n const wrappedDispose = () => {\n if (disposed) return;\n disposed = true;\n dispose();\n if (cleanup !== undefined) {\n runCleanup(cleanup);\n cleanup = undefined;\n }\n if (cleanupBag !== undefined) {\n runCleanups(cleanupBag);\n releaseArray(cleanupBag);\n cleanupBag = undefined;\n }\n };\n\n // Register in current root scope (if any)\n if (shouldRegister) {\n registerDisposer(wrappedDispose);\n }\n\n return wrappedDispose;\n}\n","/**\n * Forma Reactive - Memo\n *\n * Alias for createComputed with SolidJS/React-familiar naming.\n * A memoized derived value that only recomputes when its dependencies change.\n *\n * TC39 Signals equivalent: Signal.Computed\n */\n\nimport { createComputed } from './computed.js';\n\n/**\n * Create a memoized computed value.\n * Identical to `createComputed` — provided for React/SolidJS familiarity.\n *\n * Note: Unlike SolidJS's createComputed (which is an eager synchronous\n * side effect), both createComputed and createMemo in FormaJS are lazy\n * cached derivations — equivalent to SolidJS's createMemo. They are\n * identical.\n *\n * The computation runs lazily and caches the result. It only recomputes\n * when a signal it reads during computation changes.\n *\n * ```ts\n * const [count, setCount] = createSignal(0);\n * const doubled = createMemo(() => count() * 2);\n * console.log(doubled()); // 0\n * setCount(5);\n * console.log(doubled()); // 10\n * ```\n */\nexport const createMemo: typeof createComputed = createComputed;\n","/**\n * Forma Reactive - Batch\n *\n * Groups multiple signal updates and defers effect execution until the\n * outermost batch completes. Prevents intermediate re-renders.\n * Backed by alien-signals.\n *\n * TC39 Signals: no built-in batch — this is a userland optimization.\n */\n\nimport { startBatch, endBatch } from 'alien-signals';\n\n/**\n * Group multiple signal updates so that effects only run once after all\n * updates have been applied.\n *\n * ```ts\n * batch(() => {\n * setA(1);\n * setB(2);\n * // effects that depend on A and B won't run yet\n * });\n * // effects run here, once\n * ```\n *\n * Batches are nestable — only the outermost batch triggers the flush.\n */\nexport function batch(fn: () => void): void {\n startBatch();\n try {\n fn();\n } finally {\n endBatch();\n }\n}\n","/**\n * Forma Reactive - Untrack\n *\n * Read signals without subscribing to them in the reactive graph.\n * Essential for reading values inside effects without creating dependencies.\n *\n * TC39 Signals equivalent: Signal.subtle.untrack()\n */\n\nimport { setActiveSub } from 'alien-signals';\n\n/**\n * Execute a function without tracking signal reads.\n * Any signals read inside `fn` will NOT become dependencies of the\n * surrounding effect or computed.\n *\n * ```ts\n * createEffect(() => {\n * const a = count(); // tracked — effect re-runs when count changes\n * const b = untrack(() => other()); // NOT tracked — effect ignores other changes\n * });\n * ```\n */\nexport function untrack<T>(fn: () => T): T {\n const prev = setActiveSub(undefined);\n try {\n return fn();\n } finally {\n setActiveSub(prev);\n }\n}\n","/**\n * Forma Reactive - On\n *\n * Explicit dependency tracking for effects.\n * Only re-runs when the specified signals change, ignoring all other reads.\n *\n * SolidJS equivalent: on()\n * Vue equivalent: watch() with explicit deps\n * React equivalent: useEffect dependency array\n */\n\nimport { untrack } from './untrack.js';\n\n/**\n * Create a tracked effect body that only fires when specific dependencies change.\n *\n * Wraps a function so that only the `deps` signals are tracked.\n * All signal reads inside `fn` are untracked (won't cause re-runs).\n *\n * Use with `createEffect`:\n *\n * ```ts\n * const [a, setA] = createSignal(1);\n * const [b, setB] = createSignal(2);\n *\n * // Only re-runs when `a` changes, NOT when `b` changes:\n * createEffect(on(a, (value, prev) => {\n * console.log(`a changed: ${prev} → ${value}, b is ${b()}`);\n * }));\n *\n * setA(10); // fires: \"a changed: 1 → 10, b is 2\"\n * setB(20); // does NOT fire\n * ```\n *\n * Multiple dependencies:\n * ```ts\n * createEffect(on(\n * () => [a(), b()] as const,\n * ([aVal, bVal], prev) => { ... }\n * ));\n * ```\n */\nexport function on<T, U>(\n deps: () => T,\n fn: (value: T, prev: T | undefined) => U,\n options?: { defer?: boolean },\n): () => U | undefined {\n let prev: T | undefined;\n let isFirst = true;\n\n return () => {\n // Track only the deps\n const value = deps();\n\n if (options?.defer && isFirst) {\n isFirst = false;\n prev = value;\n return undefined;\n }\n\n // Run the body untracked so it doesn't add extra dependencies\n const result = untrack(() => fn(value, prev));\n prev = value;\n return result;\n };\n}\n","/**\n * Forma Reactive - Ref\n *\n * Mutable container that does NOT trigger reactivity.\n * Use for DOM references, previous values, instance variables —\n * anything that needs to persist across effect re-runs without\n * causing re-execution.\n *\n * React equivalent: useRef\n * SolidJS equivalent: (none — uses plain variables in setup)\n */\n\nexport interface Ref<T> {\n current: T;\n}\n\n/**\n * Create a mutable ref container.\n *\n * Unlike signals, writing to `.current` does NOT trigger effects.\n * Use when you need a stable reference across reactive scopes.\n *\n * ```ts\n * const timerRef = createRef<number | null>(null);\n *\n * createEffect(() => {\n * timerRef.current = setInterval(tick, 1000);\n * onCleanup(() => clearInterval(timerRef.current!));\n * });\n *\n * // DOM ref pattern:\n * const elRef = createRef<HTMLElement | null>(null);\n * h('div', { ref: (el) => { elRef.current = el; } });\n * ```\n */\nexport function createRef<T>(initialValue: T): Ref<T> {\n return { current: initialValue };\n}\n","/**\n * Forma Reactive - Reducer\n *\n * State machine pattern — dispatch actions to a pure reducer function.\n * Fine-grained: only the resulting state signal is reactive.\n *\n * React equivalent: useReducer\n * SolidJS equivalent: (none — uses createSignal + helpers)\n */\n\nimport { createSignal, type SignalGetter } from './signal.js';\n\nexport type Dispatch<A> = (action: A) => void;\n\n/**\n * Create a reducer — predictable state updates via dispatched actions.\n *\n * The reducer function must be pure: `(state, action) => newState`.\n * Returns a [state, dispatch] tuple.\n *\n * ```ts\n * type Action = { type: 'increment' } | { type: 'decrement' } | { type: 'reset' };\n *\n * const [count, dispatch] = createReducer(\n * (state: number, action: Action) => {\n * switch (action.type) {\n * case 'increment': return state + 1;\n * case 'decrement': return state - 1;\n * case 'reset': return 0;\n * }\n * },\n * 0,\n * );\n *\n * dispatch({ type: 'increment' }); // count() === 1\n * dispatch({ type: 'increment' }); // count() === 2\n * dispatch({ type: 'reset' }); // count() === 0\n * ```\n */\nexport function createReducer<S, A>(\n reducer: (state: S, action: A) => S,\n initialState: S,\n): [state: SignalGetter<S>, dispatch: Dispatch<A>] {\n const [state, setState] = createSignal(initialState);\n\n const dispatch: Dispatch<A> = (action) => {\n setState((prev) => reducer(prev, action));\n };\n\n return [state, dispatch];\n}\n","/**\n * Forma Reactive - Suspense Context\n *\n * Shared context stack for Suspense boundaries. Lives in the reactive layer\n * (not DOM) so that createResource can import it without circular dependencies.\n *\n * The pattern mirrors the lifecycle context stack in component/define.ts.\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SuspenseContext {\n /** Increment when a resource starts loading inside this boundary. */\n increment(): void;\n /** Decrement when a resource resolves/rejects inside this boundary. */\n decrement(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Context stack\n// ---------------------------------------------------------------------------\n\nlet currentSuspenseContext: SuspenseContext | null = null;\nconst suspenseStack: (SuspenseContext | null)[] = [];\n\nexport function pushSuspenseContext(ctx: SuspenseContext): void {\n suspenseStack.push(currentSuspenseContext);\n currentSuspenseContext = ctx;\n}\n\nexport function popSuspenseContext(): void {\n currentSuspenseContext = suspenseStack.pop() ?? null;\n}\n\n/** Get the current Suspense context (if any). Called by createResource. */\nexport function getSuspenseContext(): SuspenseContext | null {\n return currentSuspenseContext;\n}\n","/**\n * Forma Reactive - Resource\n *\n * Async data fetching primitive with reactive loading/error state.\n * Tracks a source signal and refetches when it changes.\n *\n * SolidJS equivalent: createResource\n * React equivalent: use() + Suspense (React 19), or useSWR/react-query\n */\n\nimport { createSignal, type SignalGetter } from './signal.js';\nimport { internalEffect } from './effect.js';\nimport { untrack } from './untrack.js';\nimport { getSuspenseContext } from './suspense-context.js';\n\nexport interface Resource<T> {\n /** The resolved data (or undefined while loading). */\n (): T | undefined;\n /** True while the fetcher is running. */\n loading: SignalGetter<boolean>;\n /** The error if the fetcher rejected (or undefined). */\n error: SignalGetter<unknown>;\n /** Manually refetch with the current source value. */\n refetch: () => void;\n /** Manually set the data (overrides fetcher result). */\n mutate: (value: T | undefined) => void;\n}\n\nexport interface ResourceOptions<T> {\n /** Initial value before first fetch resolves. */\n initialValue?: T;\n}\n\n/**\n * Create an async resource that fetches data reactively.\n *\n * When `source` changes, the fetcher re-runs automatically.\n * Provides reactive `loading` and `error` signals.\n *\n * ```ts\n * const [userId, setUserId] = createSignal(1);\n *\n * const user = createResource(\n * userId, // source signal\n * (id) => fetch(`/api/users/${id}`).then(r => r.json()), // fetcher\n * );\n *\n * internalEffect(() => {\n * if (user.loading()) console.log('Loading...');\n * else if (user.error()) console.log('Error:', user.error());\n * else console.log('User:', user());\n * });\n *\n * setUserId(2); // automatically refetches\n * ```\n *\n * Without a source signal (static fetch):\n * ```ts\n * const posts = createResource(\n * () => true, // constant source — fetches once\n * () => fetch('/api/posts').then(r => r.json()),\n * );\n * ```\n */\nexport function createResource<T, S = true>(\n source: SignalGetter<S>,\n fetcher: (source: S) => Promise<T>,\n options?: ResourceOptions<T>,\n): Resource<T> {\n const [data, setData] = createSignal<T | undefined>(options?.initialValue);\n const [loading, setLoading] = createSignal(false);\n const [error, setError] = createSignal<unknown>(undefined);\n\n // Capture the Suspense context at creation time (not at fetch time).\n // This is critical because the Suspense boundary pushes/pops its context\n // synchronously during children() execution.\n const suspenseCtx = getSuspenseContext();\n\n let abortController: AbortController | null = null;\n let fetchVersion = 0;\n\n const doFetch = () => {\n // Read source outside tracking to get current value\n const sourceValue = untrack(source);\n\n // Abort previous in-flight request\n if (abortController) {\n abortController.abort();\n }\n const controller = new AbortController();\n abortController = controller;\n\n const version = ++fetchVersion;\n const isLatest = () => version === fetchVersion;\n let suspensePending = false;\n\n // Notify Suspense boundary that a fetch has started\n if (suspenseCtx) {\n suspenseCtx.increment();\n suspensePending = true;\n }\n\n setLoading(true);\n setError(undefined);\n\n Promise.resolve(fetcher(sourceValue))\n .then((result) => {\n // Only apply if this is still the latest fetch and wasn't aborted.\n if (isLatest() && !controller.signal.aborted) {\n setData(() => result);\n }\n })\n .catch((err) => {\n if (isLatest() && !controller.signal.aborted) {\n // Ignore abort errors\n if (err?.name !== 'AbortError') {\n setError(err);\n }\n }\n })\n .finally(() => {\n if (suspensePending) suspenseCtx?.decrement();\n if (isLatest()) {\n setLoading(false);\n if (abortController === controller) {\n abortController = null; // Release controller for GC\n }\n }\n });\n };\n\n // Auto-fetch when source changes\n internalEffect(() => {\n source(); // track the source signal\n doFetch();\n });\n\n // Build the resource object\n const resource = (() => data()) as Resource<T>;\n resource.loading = loading;\n resource.error = error;\n resource.refetch = doFetch;\n resource.mutate = (value) => setData(() => value);\n\n return resource;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/reactive/root.ts","../src/reactive/cleanup.ts","../src/reactive/dev.ts","../src/reactive/effect.ts","../src/reactive/memo.ts","../src/reactive/batch.ts","../src/reactive/untrack.ts","../src/reactive/on.ts","../src/reactive/ref.ts","../src/reactive/reducer.ts","../src/reactive/suspense-context.ts","../src/reactive/resource.ts"],"names":["rawEffectScope","rawEffect","value"],"mappings":";;;;AAiBA,IAAI,WAAA,GAAgC,IAAA;AACpC,IAAM,YAAkC,EAAC;AAyBlC,SAAS,WAAc,EAAA,EAAmC;AAC/D,EAAA,MAAM,QAAmB,EAAE,SAAA,EAAW,EAAC,EAAG,cAAc,IAAA,EAAK;AAE7D,EAAA,SAAA,CAAU,KAAK,WAAW,CAAA;AAC1B,EAAA,WAAA,GAAc,KAAA;AAEd,EAAA,MAAM,UAAU,MAAM;AAEpB,IAAA,IAAI,MAAM,YAAA,EAAc;AACtB,MAAA,IAAI;AAAE,QAAA,KAAA,CAAM,YAAA,EAAa;AAAA,MAAG,CAAA,CAAA,MAAQ;AAAA,MAA4C;AAChF,MAAA,KAAA,CAAM,YAAA,GAAe,IAAA;AAAA,IACvB;AAEA,IAAA,KAAA,MAAW,CAAA,IAAK,MAAM,SAAA,EAAW;AAC/B,MAAA,IAAI;AAAE,QAAA,CAAA,EAAE;AAAA,MAAG,CAAA,CAAA,MAAQ;AAAA,MAAiC;AAAA,IACtD;AACA,IAAA,KAAA,CAAM,UAAU,MAAA,GAAS,CAAA;AAAA,EAC3B,CAAA;AAEA,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AAEF,IAAA,KAAA,CAAM,YAAA,GAAeA,YAAe,MAAM;AACxC,MAAA,MAAA,GAAS,GAAG,OAAO,CAAA;AAAA,IACrB,CAAC,CAAA;AAAA,EACH,CAAA,SAAE;AACA,IAAA,WAAA,GAAc,SAAA,CAAU,KAAI,IAAK,IAAA;AAAA,EACnC;AAEA,EAAA,OAAO,MAAA;AACT;AAKO,SAAS,iBAAiB,OAAA,EAA2B;AAC1D,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,WAAA,CAAY,SAAA,CAAU,KAAK,OAAO,CAAA;AAAA,EACpC;AACF;AAKO,SAAS,aAAA,GAAyB;AACvC,EAAA,OAAO,WAAA,KAAgB,IAAA;AACzB;;;AC5EA,IAAI,uBAAA,GAA4C,IAAA;AAgBzC,SAAS,UAAU,EAAA,EAAsB;AAC9C,EAAA,uBAAA,GAA0B,EAAE,CAAA;AAC9B;AAKO,SAAS,oBAAoB,SAAA,EAA+C;AACjF,EAAA,MAAM,IAAA,GAAO,uBAAA;AACb,EAAA,uBAAA,GAA0B,SAAA;AAC1B,EAAA,OAAO,IAAA;AACT;;;AC/BO,IAAM,UAAmB,OAAO,OAAA,KAAY,cAC9C,OAAA,CAAS,GAAA,EAAK,aAAa,YAAA,GAC5B;AAQJ,IAAI,aAAA,GAAqC,IAAA;AAalC,SAAS,QAAQ,OAAA,EAA6B;AACnD,EAAA,aAAA,GAAgB,OAAA;AAClB;AAGO,SAAS,WAAA,CAAY,OAAgB,MAAA,EAAuB;AACjE,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,IAAI;AAAE,MAAA,aAAA,CAAc,OAAO,MAAA,GAAS,EAAE,MAAA,EAAO,GAAI,EAAE,CAAA;AAAA,IAAG,CAAA,CAAA,MAAQ;AAAA,IAA8B;AAAA,EAC9F;AACA,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,QAAA,EAAW,MAAA,IAAU,SAAS,WAAW,KAAK,CAAA;AAAA,EAC9D;AACF;AC1BA,IAAM,SAAA,GAAY,EAAA;AAClB,IAAM,kBAAA,GAAqB,GAAA;AAC3B,IAAM,OAAyB,EAAC;AAChC,KAAA,IAAS,CAAA,GAAI,GAAG,CAAA,GAAI,SAAA,EAAW,KAAK,IAAA,CAAK,IAAA,CAAK,EAAE,CAAA;AAChD,IAAI,OAAA,GAAU,SAAA;AAEd,SAAS,YAAA,GAA+B;AACtC,EAAA,IAAI,UAAU,CAAA,EAAG;AACf,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,EAAE,OAAO,CAAA;AAC1B,IAAA,GAAA,CAAI,MAAA,GAAS,CAAA;AACb,IAAA,OAAO,GAAA;AAAA,EACT;AACA,EAAA,OAAO,EAAC;AACV;AAEA,SAAS,aAAa,GAAA,EAA2B;AAC/C,EAAA,GAAA,CAAI,MAAA,GAAS,CAAA;AACb,EAAA,IAAI,UAAU,SAAA,EAAW;AACvB,IAAA,IAAA,CAAK,SAAS,CAAA,GAAI,GAAA;AAAA,EACpB;AACF;AAMA,SAAS,WAAW,EAAA,EAAoC;AACtD,EAAA,IAAI,OAAO,MAAA,EAAW;AACtB,EAAA,IAAI;AACF,IAAA,EAAA,EAAG;AAAA,EACL,SAAS,CAAA,EAAG;AACV,IAAA,WAAA,CAAY,GAAG,gBAAgB,CAAA;AAAA,EACjC;AACF;AAEA,SAAS,YAAY,GAAA,EAAuC;AAC1D,EAAA,IAAI,QAAQ,MAAA,EAAW;AACvB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,QAAQ,CAAA,EAAA,EAAK;AACnC,IAAA,IAAI;AAAE,MAAA,GAAA,CAAI,CAAC,CAAA,EAAG;AAAA,IAAG,SAAS,CAAA,EAAG;AAAE,MAAA,WAAA,CAAY,GAAG,gBAAgB,CAAA;AAAA,IAAG;AAAA,EACnE;AACF;AA+BO,SAAS,eAAe,EAAA,EAA4B;AACzD,EAAA,MAAM,OAAA,GAAUC,OAAU,EAAE,CAAA;AAC5B,EAAA,IAAI,eAAc,EAAG;AACnB,IAAA,gBAAA,CAAiB,OAAO,CAAA;AAAA,EAC1B;AACA,EAAA,OAAO,OAAA;AACT;AAEO,SAAS,aAAa,EAAA,EAA2C;AACtE,EAAA,MAAM,iBAAiB,aAAA,EAAc;AAIrC,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,UAAA;AACJ,EAAA,IAAI,WAAA;AACJ,EAAA,IAAI,cAAA;AAEJ,EAAA,MAAM,UAAA,GAAa,CAAC,EAAA,KAAmB;AACrC,IAAA,IAAI,mBAAmB,MAAA,EAAW;AAChC,MAAA,cAAA,CAAe,KAAK,EAAE,CAAA;AACtB,MAAA;AAAA,IACF;AACA,IAAA,IAAI,gBAAgB,MAAA,EAAW;AAC7B,MAAA,MAAM,MAAM,YAAA,EAAa;AACzB,MAAA,GAAA,CAAI,IAAA,CAAK,aAAa,EAAE,CAAA;AACxB,MAAA,WAAA,GAAc,MAAA;AACd,MAAA,cAAA,GAAiB,GAAA;AACjB,MAAA;AAAA,IACF;AACA,IAAA,WAAA,GAAc,EAAA;AAAA,EAChB,CAAA;AASA,EAAA,IAAI,gBAAA,GAAmB,KAAA;AACvB,EAAA,IAAI,QAAA,GAAW,IAAA;AACf,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,IAAI,cAAA,GAAiB,KAAA;AAErB,EAAA,MAAM,UAAU,MAAM;AAEpB,IAAA,IAAI,YAAY,MAAA,EAAW;AACzB,MAAA,UAAA,CAAW,OAAO,CAAA;AAClB,MAAA,OAAA,GAAU,MAAA;AAAA,IACZ;AACA,IAAA,IAAI,eAAe,MAAA,EAAW;AAC5B,MAAA,WAAA,CAAY,UAAU,CAAA;AACtB,MAAA,YAAA,CAAa,UAAU,CAAA;AACvB,MAAA,UAAA,GAAa,MAAA;AAAA,IACf;AAIA,IAAA,IAAI,gBAAA,EAAkB;AACpB,MAAA,IAAI;AAAE,QAAA,EAAA,EAAG;AAAA,MAAG,SAAS,CAAA,EAAG;AAAE,QAAA,WAAA,CAAY,GAAG,QAAQ,CAAA;AAAA,MAAG;AACpD,MAAA;AAAA,IACF;AAEA,IAAA,WAAA,GAAc,MAAA;AACd,IAAA,cAAA,GAAiB,MAAA;AAGjB,IAAA,MAAM,aAAA,GAAgB,oBAAoB,UAAU,CAAA;AAEpD,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,EAAA,EAAG;AAElB,MAAA,IAAI,OAAO,WAAW,UAAA,EAAY;AAChC,QAAA,UAAA,CAAW,MAAoB,CAAA;AAAA,MACjC;AAGA,MAAA,IAAI,WAAA,KAAgB,KAAA,CAAA,IAAa,cAAA,KAAmB,KAAA,CAAA,EAAW;AAE7D,QAAA,IAAI,UAAU,gBAAA,GAAmB,IAAA;AACjC,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,mBAAmB,KAAA,CAAA,EAAW;AAChC,QAAA,UAAA,GAAa,cAAA;AAAA,MACf,CAAA,MAAO;AACL,QAAA,OAAA,GAAU,WAAA;AAAA,MACZ;AAAA,IACF,SAAS,CAAA,EAAG;AACV,MAAA,WAAA,CAAY,GAAG,QAAQ,CAAA;AAEvB,MAAA,IAAI,mBAAmB,MAAA,EAAW;AAChC,QAAA,UAAA,GAAa,cAAA;AAAA,MACf,CAAA,MAAO;AACL,QAAA,OAAA,GAAU,WAAA;AAAA,MACZ;AAAA,IACF,CAAA,SAAE;AACA,MAAA,mBAAA,CAAoB,aAAa,CAAA;AACjC,MAAA,QAAA,GAAW,KAAA;AAAA,IACb;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,SAAS,MAAM;AACnB,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,cAAA,GAAiB,IAAA;AACjB,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,GAAU,IAAA;AACV,IAAA,IAAI;AACF,MAAA,IAAI,aAAA,GAAgB,CAAA;AACpB,MAAA,GAAG;AACD,QAAA,cAAA,GAAiB,KAAA;AACjB,QAAA,OAAA,EAAQ;AACR,QAAA,IAAI,cAAA,EAAgB;AAClB,UAAA,aAAA,EAAA;AACA,UAAA,IAAI,iBAAiB,kBAAA,EAAoB;AACvC,YAAA,WAAA;AAAA,cACE,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,kBAAkB,CAAA,gBAAA,CAAkB,CAAA;AAAA,cACvE;AAAA,aACF;AACA,YAAA,cAAA,GAAiB,KAAA;AAAA,UACnB;AAAA,QACF;AAAA,MACF,CAAA,QAAS,cAAA;AAAA,IACX,CAAA,SAAE;AACA,MAAA,OAAA,GAAU,KAAA;AAAA,IACZ;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,OAAA,GAAUA,OAAU,MAAM,CAAA;AAGhC,EAAA,IAAI,QAAA,GAAW,KAAA;AACf,EAAA,MAAM,iBAAiB,MAAM;AAC3B,IAAA,IAAI,QAAA,EAAU;AACd,IAAA,QAAA,GAAW,IAAA;AACX,IAAA,OAAA,EAAQ;AACR,IAAA,IAAI,YAAY,MAAA,EAAW;AACzB,MAAA,UAAA,CAAW,OAAO,CAAA;AAClB,MAAA,OAAA,GAAU,MAAA;AAAA,IACZ;AACA,IAAA,IAAI,eAAe,MAAA,EAAW;AAC5B,MAAA,WAAA,CAAY,UAAU,CAAA;AACtB,MAAA,YAAA,CAAa,UAAU,CAAA;AACvB,MAAA,UAAA,GAAa,MAAA;AAAA,IACf;AAAA,EACF,CAAA;AAGA,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,gBAAA,CAAiB,cAAc,CAAA;AAAA,EACjC;AAEA,EAAA,OAAO,cAAA;AACT;;;ACtNO,IAAM,UAAA,GAAoC;ACJ1C,SAAS,MAAM,EAAA,EAAsB;AAC1C,EAAA,UAAA,EAAW;AACX,EAAA,IAAI;AACF,IAAA,EAAA,EAAG;AAAA,EACL,CAAA,SAAE;AACA,IAAA,QAAA,EAAS;AAAA,EACX;AACF;ACXO,SAAS,QAAW,EAAA,EAAgB;AACzC,EAAA,MAAM,IAAA,GAAO,aAAa,MAAS,CAAA;AACnC,EAAA,IAAI;AACF,IAAA,OAAO,EAAA,EAAG;AAAA,EACZ,CAAA,SAAE;AACA,IAAA,YAAA,CAAa,IAAI,CAAA;AAAA,EACnB;AACF;;;ACYO,SAAS,EAAA,CACd,IAAA,EACA,EAAA,EACA,OAAA,EACqB;AACrB,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI,OAAA,GAAU,IAAA;AAEd,EAAA,OAAO,MAAM;AAEX,IAAA,MAAMC,SAAQ,IAAA,EAAK;AAEnB,IAAA,IAAI,OAAA,EAAS,SAAS,OAAA,EAAS;AAC7B,MAAA,OAAA,GAAU,KAAA;AACV,MAAA,IAAA,GAAOA,MAAAA;AACP,MAAA,OAAO,MAAA;AAAA,IACT;AAGA,IAAA,MAAM,SAAS,OAAA,CAAQ,MAAM,EAAA,CAAGA,MAAAA,EAAO,IAAI,CAAC,CAAA;AAC5C,IAAA,IAAA,GAAOA,MAAAA;AACP,IAAA,OAAO,MAAA;AAAA,EACT,CAAA;AACF;;;AC9BO,SAAS,UAAa,YAAA,EAAyB;AACpD,EAAA,OAAO,EAAE,SAAS,YAAA,EAAa;AACjC;;;ACEO,SAAS,aAAA,CACd,SACA,YAAA,EACiD;AACjD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,aAAa,YAAY,CAAA;AAEnD,EAAA,MAAM,QAAA,GAAwB,CAAC,MAAA,KAAW;AACxC,IAAA,QAAA,CAAS,CAAC,IAAA,KAAS,OAAA,CAAQ,IAAA,EAAM,MAAM,CAAC,CAAA;AAAA,EAC1C,CAAA;AAEA,EAAA,OAAO,CAAC,OAAO,QAAQ,CAAA;AACzB;;;AC1BA,IAAI,sBAAA,GAAiD,IAAA;AACrD,IAAM,gBAA4C,EAAC;AAE5C,SAAS,oBAAoB,GAAA,EAA4B;AAC9D,EAAA,aAAA,CAAc,KAAK,sBAAsB,CAAA;AACzC,EAAA,sBAAA,GAAyB,GAAA;AAC3B;AAEO,SAAS,kBAAA,GAA2B;AACzC,EAAA,sBAAA,GAAyB,aAAA,CAAc,KAAI,IAAK,IAAA;AAClD;AAGO,SAAS,kBAAA,GAA6C;AAC3D,EAAA,OAAO,sBAAA;AACT;;;ACyBO,SAAS,cAAA,CACd,MAAA,EACA,OAAA,EACA,OAAA,EACa;AACb,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,YAAA,CAA4B,SAAS,YAAY,CAAA;AACzE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,aAAa,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,aAAsB,MAAS,CAAA;AAKzD,EAAA,MAAM,cAAc,kBAAA,EAAmB;AAEvC,EAAA,IAAI,eAAA,GAA0C,IAAA;AAC9C,EAAA,IAAI,YAAA,GAAe,CAAA;AAEnB,EAAA,MAAM,UAAU,MAAM;AAEpB,IAAA,MAAM,WAAA,GAAc,QAAQ,MAAM,CAAA;AAGlC,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,eAAA,CAAgB,KAAA,EAAM;AAAA,IACxB;AACA,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,eAAA,GAAkB,UAAA;AAElB,IAAA,MAAM,UAAU,EAAE,YAAA;AAClB,IAAA,MAAM,QAAA,GAAW,MAAM,OAAA,KAAY,YAAA;AACnC,IAAA,IAAI,eAAA,GAAkB,KAAA;AAGtB,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,WAAA,CAAY,SAAA,EAAU;AACtB,MAAA,eAAA,GAAkB,IAAA;AAAA,IACpB;AAEA,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,QAAA,CAAS,MAAS,CAAA;AAElB,IAAA,OAAA,CAAQ,QAAQ,OAAA,CAAQ,WAAW,CAAC,CAAA,CACjC,IAAA,CAAK,CAAC,MAAA,KAAW;AAEhB,MAAA,IAAI,QAAA,EAAS,IAAK,CAAC,UAAA,CAAW,OAAO,OAAA,EAAS;AAC5C,QAAA,OAAA,CAAQ,MAAM,MAAM,CAAA;AAAA,MACtB;AAAA,IACF,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,GAAA,KAAQ;AACd,MAAA,IAAI,QAAA,EAAS,IAAK,CAAC,UAAA,CAAW,OAAO,OAAA,EAAS;AAE5C,QAAA,IAAI,GAAA,EAAK,SAAS,YAAA,EAAc;AAC9B,UAAA,QAAA,CAAS,GAAG,CAAA;AAAA,QACd;AAAA,MACF;AAAA,IACF,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,IAAI,eAAA,eAA8B,SAAA,EAAU;AAC5C,MAAA,IAAI,UAAS,EAAG;AACd,QAAA,UAAA,CAAW,KAAK,CAAA;AAChB,QAAA,IAAI,oBAAoB,UAAA,EAAY;AAClC,UAAA,eAAA,GAAkB,IAAA;AAAA,QACpB;AAAA,MACF;AAAA,IACF,CAAC,CAAA;AAAA,EACL,CAAA;AAGA,EAAA,cAAA,CAAe,MAAM;AACnB,IAAA,MAAA,EAAO;AACP,IAAA,OAAA,EAAQ;AAAA,EACV,CAAC,CAAA;AAGD,EAAA,MAAM,QAAA,IAAY,MAAM,IAAA,EAAK,CAAA;AAC7B,EAAA,QAAA,CAAS,OAAA,GAAU,OAAA;AACnB,EAAA,QAAA,CAAS,KAAA,GAAQ,KAAA;AACjB,EAAA,QAAA,CAAS,OAAA,GAAU,OAAA;AACnB,EAAA,QAAA,CAAS,MAAA,GAAS,CAACA,MAAAA,KAAU,OAAA,CAAQ,MAAMA,MAAK,CAAA;AAEhD,EAAA,OAAO,QAAA;AACT","file":"chunk-OUVOAYIO.js","sourcesContent":["/**\n * Forma Reactive - Root\n *\n * Explicit reactive ownership scope. All effects created inside a root\n * are automatically disposed when the root is torn down.\n *\n * Uses alien-signals' `effectScope` under the hood for native graph-level\n * effect tracking, with a userland disposer list for non-effect cleanup\n * (e.g., event listeners, DOM references, timers).\n */\n\nimport { effectScope as rawEffectScope } from 'alien-signals';\n\n// ---------------------------------------------------------------------------\n// Root scope tracking\n// ---------------------------------------------------------------------------\n\nlet currentRoot: RootScope | null = null;\nconst rootStack: (RootScope | null)[] = [];\n\ninterface RootScope {\n /** Userland disposers (event listeners, DOM refs, timers, etc.) */\n disposers: (() => void)[];\n /** alien-signals effect scope dispose — tears down all reactive effects */\n scopeDispose: (() => void) | null;\n}\n\n/**\n * Create a reactive root scope.\n *\n * All effects created (via `createEffect`) inside the callback are tracked\n * at both the reactive graph level (via alien-signals effectScope) and the\n * userland level (via registerDisposer). The returned `dispose` function\n * tears down everything.\n *\n * ```ts\n * const dispose = createRoot(() => {\n * createEffect(() => console.log(count()));\n * createEffect(() => console.log(name()));\n * });\n * // later: dispose() stops both effects\n * ```\n */\nexport function createRoot<T>(fn: (dispose: () => void) => T): T {\n const scope: RootScope = { disposers: [], scopeDispose: null };\n\n rootStack.push(currentRoot);\n currentRoot = scope;\n\n const dispose = () => {\n // Dispose alien-signals effect scope first (reactive graph cleanup)\n if (scope.scopeDispose) {\n try { scope.scopeDispose(); } catch { /* ensure userland disposers still run */ }\n scope.scopeDispose = null;\n }\n // Then run userland disposers\n for (const d of scope.disposers) {\n try { d(); } catch { /* ensure all disposers run */ }\n }\n scope.disposers.length = 0;\n };\n\n let result: T;\n try {\n // Wrap in alien-signals effectScope for native effect tracking\n scope.scopeDispose = rawEffectScope(() => {\n result = fn(dispose);\n });\n } finally {\n currentRoot = rootStack.pop() ?? null;\n }\n\n return result!;\n}\n\n/**\n * @internal — called by createEffect to register disposers in the current root.\n */\nexport function registerDisposer(dispose: () => void): void {\n if (currentRoot) {\n currentRoot.disposers.push(dispose);\n }\n}\n\n/**\n * @internal — check if we're inside a root scope.\n */\nexport function hasActiveRoot(): boolean {\n return currentRoot !== null;\n}\n","/**\n * Forma Reactive - Cleanup\n *\n * Register cleanup functions within reactive scopes.\n * Inspired by SolidJS onCleanup().\n */\n\n// ---------------------------------------------------------------------------\n// Cleanup context tracking\n// ---------------------------------------------------------------------------\n\ntype CleanupCollector = ((fn: () => void) => void) | null;\n\nlet currentCleanupCollector: CleanupCollector = null;\n\n/**\n * Register a cleanup function in the current reactive scope.\n * The cleanup runs before the effect re-executes and on disposal.\n *\n * More composable than returning a cleanup from the effect function,\n * since it can be called from helper functions.\n *\n * ```ts\n * createEffect(() => {\n * const timer = setInterval(tick, 1000);\n * onCleanup(() => clearInterval(timer));\n * });\n * ```\n */\nexport function onCleanup(fn: () => void): void {\n currentCleanupCollector?.(fn);\n}\n\n/**\n * @internal — Set the cleanup collector for the current effect execution.\n */\nexport function setCleanupCollector(collector: CleanupCollector): CleanupCollector {\n const prev = currentCleanupCollector;\n currentCleanupCollector = collector;\n return prev;\n}\n","/**\n * Forma Reactive - Dev Mode\n *\n * Development utilities stripped from production builds via __DEV__ flag.\n * Bundlers replace __DEV__ with false → dead-code elimination removes all dev paths.\n */\n\n// __DEV__ is replaced by bundler (tsup define). Defaults to true for unbundled usage.\ndeclare const process: { env?: Record<string, string | undefined> } | undefined;\nexport const __DEV__: boolean = typeof process !== 'undefined'\n ? (process!.env?.NODE_ENV !== 'production')\n : true;\n\n// ---------------------------------------------------------------------------\n// Global error handler\n// ---------------------------------------------------------------------------\n\nexport type ErrorHandler = (error: unknown, info?: { source?: string }) => void;\n\nlet _errorHandler: ErrorHandler | null = null;\n\n/**\n * Install a global error handler for FormaJS reactive errors.\n * Called when effects, computeds, or event handlers throw.\n *\n * ```ts\n * onError((err, info) => {\n * console.error(`[${info?.source}]`, err);\n * Sentry.captureException(err);\n * });\n * ```\n */\nexport function onError(handler: ErrorHandler): void {\n _errorHandler = handler;\n}\n\n/** @internal */\nexport function reportError(error: unknown, source?: string): void {\n if (_errorHandler) {\n try { _errorHandler(error, source ? { source } : {}); } catch { /* prevent infinite loop */ }\n }\n if (__DEV__) {\n console.error(`[forma] ${source ?? 'Unknown'} error:`, error);\n }\n}\n","/**\n * Forma Reactive - Effect\n *\n * Side-effectful reactive computation that auto-tracks signal dependencies.\n * Backed by alien-signals for automatic dependency tracking.\n *\n * TC39 Signals equivalent: Signal.subtle.Watcher (effect is a userland concept)\n */\n\nimport { effect as rawEffect } from 'alien-signals';\nimport { hasActiveRoot, registerDisposer } from './root.js';\nimport { setCleanupCollector } from './cleanup.js';\nimport { reportError } from './dev.js';\n\n// ---------------------------------------------------------------------------\n// Cleanup array pool — avoids allocating a new array every effect re-run\n// ---------------------------------------------------------------------------\n\nconst POOL_SIZE = 32;\nconst MAX_REENTRANT_RUNS = 100;\nconst pool: (() => void)[][] = [];\nfor (let i = 0; i < POOL_SIZE; i++) pool.push([]);\nlet poolIdx = POOL_SIZE;\n\nfunction acquireArray(): (() => void)[] {\n if (poolIdx > 0) {\n const arr = pool[--poolIdx]!;\n arr.length = 0;\n return arr;\n }\n return [];\n}\n\nfunction releaseArray(arr: (() => void)[]): void {\n arr.length = 0;\n if (poolIdx < POOL_SIZE) {\n pool[poolIdx++] = arr;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Unified cleanup runner — single function for both re-run and dispose paths\n// ---------------------------------------------------------------------------\n\nfunction runCleanup(fn: (() => void) | undefined): void {\n if (fn === undefined) return;\n try {\n fn();\n } catch (e) {\n reportError(e, 'effect cleanup');\n }\n}\n\nfunction runCleanups(bag: (() => void)[] | undefined): void {\n if (bag === undefined) return;\n for (let i = 0; i < bag.length; i++) {\n try { bag[i]!(); } catch (e) { reportError(e, 'effect cleanup'); }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a reactive effect that auto-tracks signal dependencies.\n *\n * The provided function runs immediately and re-runs whenever any signal it\n * reads changes. If the function returns a cleanup function, that cleanup is\n * called before each re-run and on disposal.\n *\n * Additionally, `onCleanup()` can be called inside the effect to register\n * cleanup functions composably.\n *\n * Returns a dispose function that stops the effect.\n */\n/**\n * @internal — Lightweight effect for Forma's internal DOM bindings.\n *\n * Bypasses createEffect's cleanup infrastructure (pool, collector, error\n * reporting, engine compression) since internal effects never use\n * onCleanup() or return cleanup functions. This saves ~4 function calls\n * per effect creation and per re-run.\n *\n * ONLY use for effects that:\n * 1. Never call onCleanup()\n * 2. Never return a cleanup function\n * 3. Contain simple \"read signal → write DOM\" logic\n */\nexport function internalEffect(fn: () => void): () => void {\n const dispose = rawEffect(fn);\n if (hasActiveRoot()) {\n registerDisposer(dispose);\n }\n return dispose;\n}\n\nexport function createEffect(fn: () => void | (() => void)): () => void {\n const shouldRegister = hasActiveRoot();\n\n // Most effects have zero or one cleanup. Track the single-cleanup case\n // without array allocation; only promote to pooled array when needed.\n let cleanup: (() => void) | undefined;\n let cleanupBag: (() => void)[] | undefined;\n let nextCleanup: (() => void) | undefined;\n let nextCleanupBag: (() => void)[] | undefined;\n\n const addCleanup = (cb: () => void) => {\n if (nextCleanupBag !== undefined) {\n nextCleanupBag.push(cb);\n return;\n }\n if (nextCleanup !== undefined) {\n const bag = acquireArray();\n bag.push(nextCleanup, cb);\n nextCleanup = undefined;\n nextCleanupBag = bag;\n return;\n }\n nextCleanup = cb;\n };\n\n // \"Engine Compression\" exploit: most effects never use cleanup (onCleanup()\n // or return value). After the first clean run, we know this effect is\n // \"cleanup-free\" and can skip the entire cleanup infrastructure on re-runs.\n // This saves 4 function calls per re-run: acquireArray, setCleanupCollector,\n // releaseArray, and bag inspection. Like the engine compression ratio exploit —\n // the \"rules\" say we should always prepare for cleanup, but we measure at\n // \"room temperature\" (first run) and exploit the gap.\n let skipCleanupInfra = false;\n let firstRun = true;\n let running = false;\n let rerunRequested = false;\n\n const runOnce = () => {\n // Run and clear previous cleanups (only if any exist).\n if (cleanup !== undefined) {\n runCleanup(cleanup);\n cleanup = undefined;\n }\n if (cleanupBag !== undefined) {\n runCleanups(cleanupBag);\n releaseArray(cleanupBag);\n cleanupBag = undefined;\n }\n\n // Ultra-fast path: this effect has proven it doesn't use cleanup.\n // Skip acquireArray + setCleanupCollector + bag checks + releaseArray.\n if (skipCleanupInfra) {\n try { fn(); } catch (e) { reportError(e, 'effect'); }\n return;\n }\n\n nextCleanup = undefined;\n nextCleanupBag = undefined;\n\n // Full path: install collector for onCleanup() calls.\n const prevCollector = setCleanupCollector(addCleanup);\n\n try {\n const result = fn();\n\n if (typeof result === 'function') {\n addCleanup(result as () => void);\n }\n\n // Hot path: no cleanups registered or returned — enable ultra-fast path.\n if (nextCleanup === undefined && nextCleanupBag === undefined) {\n // First clean run → enable ultra-fast path for all subsequent runs\n if (firstRun) skipCleanupInfra = true;\n return;\n }\n\n if (nextCleanupBag !== undefined) {\n cleanupBag = nextCleanupBag;\n } else {\n cleanup = nextCleanup;\n }\n } catch (e) {\n reportError(e, 'effect');\n\n if (nextCleanupBag !== undefined) {\n cleanupBag = nextCleanupBag;\n } else {\n cleanup = nextCleanup;\n }\n } finally {\n setCleanupCollector(prevCollector);\n firstRun = false;\n }\n };\n\n const safeFn = () => {\n if (running) {\n rerunRequested = true;\n return;\n }\n\n running = true;\n try {\n let reentrantRuns = 0;\n do {\n rerunRequested = false;\n runOnce();\n if (rerunRequested) {\n reentrantRuns++;\n if (reentrantRuns >= MAX_REENTRANT_RUNS) {\n reportError(\n new Error(`createEffect exceeded ${MAX_REENTRANT_RUNS} re-entrant runs`),\n 'effect',\n );\n rerunRequested = false;\n }\n }\n } while (rerunRequested);\n } finally {\n running = false;\n }\n };\n\n const dispose = rawEffect(safeFn);\n\n // Wrap dispose to also run final cleanups\n let disposed = false;\n const wrappedDispose = () => {\n if (disposed) return;\n disposed = true;\n dispose();\n if (cleanup !== undefined) {\n runCleanup(cleanup);\n cleanup = undefined;\n }\n if (cleanupBag !== undefined) {\n runCleanups(cleanupBag);\n releaseArray(cleanupBag);\n cleanupBag = undefined;\n }\n };\n\n // Register in current root scope (if any)\n if (shouldRegister) {\n registerDisposer(wrappedDispose);\n }\n\n return wrappedDispose;\n}\n","/**\n * Forma Reactive - Memo\n *\n * Alias for createComputed with SolidJS/React-familiar naming.\n * A memoized derived value that only recomputes when its dependencies change.\n *\n * TC39 Signals equivalent: Signal.Computed\n */\n\nimport { createComputed } from './computed.js';\n\n/**\n * Create a memoized computed value.\n * Identical to `createComputed` — provided for React/SolidJS familiarity.\n *\n * Note: Unlike SolidJS's createComputed (which is an eager synchronous\n * side effect), both createComputed and createMemo in FormaJS are lazy\n * cached derivations — equivalent to SolidJS's createMemo. They are\n * identical.\n *\n * The computation runs lazily and caches the result. It only recomputes\n * when a signal it reads during computation changes.\n *\n * ```ts\n * const [count, setCount] = createSignal(0);\n * const doubled = createMemo(() => count() * 2);\n * console.log(doubled()); // 0\n * setCount(5);\n * console.log(doubled()); // 10\n * ```\n */\nexport const createMemo: typeof createComputed = createComputed;\n","/**\n * Forma Reactive - Batch\n *\n * Groups multiple signal updates and defers effect execution until the\n * outermost batch completes. Prevents intermediate re-renders.\n * Backed by alien-signals.\n *\n * TC39 Signals: no built-in batch — this is a userland optimization.\n */\n\nimport { startBatch, endBatch } from 'alien-signals';\n\n/**\n * Group multiple signal updates so that effects only run once after all\n * updates have been applied.\n *\n * ```ts\n * batch(() => {\n * setA(1);\n * setB(2);\n * // effects that depend on A and B won't run yet\n * });\n * // effects run here, once\n * ```\n *\n * Batches are nestable — only the outermost batch triggers the flush.\n */\nexport function batch(fn: () => void): void {\n startBatch();\n try {\n fn();\n } finally {\n endBatch();\n }\n}\n","/**\n * Forma Reactive - Untrack\n *\n * Read signals without subscribing to them in the reactive graph.\n * Essential for reading values inside effects without creating dependencies.\n *\n * TC39 Signals equivalent: Signal.subtle.untrack()\n */\n\nimport { setActiveSub } from 'alien-signals';\n\n/**\n * Execute a function without tracking signal reads.\n * Any signals read inside `fn` will NOT become dependencies of the\n * surrounding effect or computed.\n *\n * ```ts\n * createEffect(() => {\n * const a = count(); // tracked — effect re-runs when count changes\n * const b = untrack(() => other()); // NOT tracked — effect ignores other changes\n * });\n * ```\n */\nexport function untrack<T>(fn: () => T): T {\n const prev = setActiveSub(undefined);\n try {\n return fn();\n } finally {\n setActiveSub(prev);\n }\n}\n","/**\n * Forma Reactive - On\n *\n * Explicit dependency tracking for effects.\n * Only re-runs when the specified signals change, ignoring all other reads.\n *\n * SolidJS equivalent: on()\n * Vue equivalent: watch() with explicit deps\n * React equivalent: useEffect dependency array\n */\n\nimport { untrack } from './untrack.js';\n\n/**\n * Create a tracked effect body that only fires when specific dependencies change.\n *\n * Wraps a function so that only the `deps` signals are tracked.\n * All signal reads inside `fn` are untracked (won't cause re-runs).\n *\n * Use with `createEffect`:\n *\n * ```ts\n * const [a, setA] = createSignal(1);\n * const [b, setB] = createSignal(2);\n *\n * // Only re-runs when `a` changes, NOT when `b` changes:\n * createEffect(on(a, (value, prev) => {\n * console.log(`a changed: ${prev} → ${value}, b is ${b()}`);\n * }));\n *\n * setA(10); // fires: \"a changed: 1 → 10, b is 2\"\n * setB(20); // does NOT fire\n * ```\n *\n * Multiple dependencies:\n * ```ts\n * createEffect(on(\n * () => [a(), b()] as const,\n * ([aVal, bVal], prev) => { ... }\n * ));\n * ```\n */\nexport function on<T, U>(\n deps: () => T,\n fn: (value: T, prev: T | undefined) => U,\n options?: { defer?: boolean },\n): () => U | undefined {\n let prev: T | undefined;\n let isFirst = true;\n\n return () => {\n // Track only the deps\n const value = deps();\n\n if (options?.defer && isFirst) {\n isFirst = false;\n prev = value;\n return undefined;\n }\n\n // Run the body untracked so it doesn't add extra dependencies\n const result = untrack(() => fn(value, prev));\n prev = value;\n return result;\n };\n}\n","/**\n * Forma Reactive - Ref\n *\n * Mutable container that does NOT trigger reactivity.\n * Use for DOM references, previous values, instance variables —\n * anything that needs to persist across effect re-runs without\n * causing re-execution.\n *\n * React equivalent: useRef\n * SolidJS equivalent: (none — uses plain variables in setup)\n */\n\nexport interface Ref<T> {\n current: T;\n}\n\n/**\n * Create a mutable ref container.\n *\n * Unlike signals, writing to `.current` does NOT trigger effects.\n * Use when you need a stable reference across reactive scopes.\n *\n * ```ts\n * const timerRef = createRef<number | null>(null);\n *\n * createEffect(() => {\n * timerRef.current = setInterval(tick, 1000);\n * onCleanup(() => clearInterval(timerRef.current!));\n * });\n *\n * // DOM ref pattern:\n * const elRef = createRef<HTMLElement | null>(null);\n * h('div', { ref: (el) => { elRef.current = el; } });\n * ```\n */\nexport function createRef<T>(initialValue: T): Ref<T> {\n return { current: initialValue };\n}\n","/**\n * Forma Reactive - Reducer\n *\n * State machine pattern — dispatch actions to a pure reducer function.\n * Fine-grained: only the resulting state signal is reactive.\n *\n * React equivalent: useReducer\n * SolidJS equivalent: (none — uses createSignal + helpers)\n */\n\nimport { createSignal, type SignalGetter } from './signal.js';\n\nexport type Dispatch<A> = (action: A) => void;\n\n/**\n * Create a reducer — predictable state updates via dispatched actions.\n *\n * The reducer function must be pure: `(state, action) => newState`.\n * Returns a [state, dispatch] tuple.\n *\n * ```ts\n * type Action = { type: 'increment' } | { type: 'decrement' } | { type: 'reset' };\n *\n * const [count, dispatch] = createReducer(\n * (state: number, action: Action) => {\n * switch (action.type) {\n * case 'increment': return state + 1;\n * case 'decrement': return state - 1;\n * case 'reset': return 0;\n * }\n * },\n * 0,\n * );\n *\n * dispatch({ type: 'increment' }); // count() === 1\n * dispatch({ type: 'increment' }); // count() === 2\n * dispatch({ type: 'reset' }); // count() === 0\n * ```\n */\nexport function createReducer<S, A>(\n reducer: (state: S, action: A) => S,\n initialState: S,\n): [state: SignalGetter<S>, dispatch: Dispatch<A>] {\n const [state, setState] = createSignal(initialState);\n\n const dispatch: Dispatch<A> = (action) => {\n setState((prev) => reducer(prev, action));\n };\n\n return [state, dispatch];\n}\n","/**\n * Forma Reactive - Suspense Context\n *\n * Shared context stack for Suspense boundaries. Lives in the reactive layer\n * (not DOM) so that createResource can import it without circular dependencies.\n *\n * The pattern mirrors the lifecycle context stack in component/define.ts.\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SuspenseContext {\n /** Increment when a resource starts loading inside this boundary. */\n increment(): void;\n /** Decrement when a resource resolves/rejects inside this boundary. */\n decrement(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Context stack\n// ---------------------------------------------------------------------------\n\nlet currentSuspenseContext: SuspenseContext | null = null;\nconst suspenseStack: (SuspenseContext | null)[] = [];\n\nexport function pushSuspenseContext(ctx: SuspenseContext): void {\n suspenseStack.push(currentSuspenseContext);\n currentSuspenseContext = ctx;\n}\n\nexport function popSuspenseContext(): void {\n currentSuspenseContext = suspenseStack.pop() ?? null;\n}\n\n/** Get the current Suspense context (if any). Called by createResource. */\nexport function getSuspenseContext(): SuspenseContext | null {\n return currentSuspenseContext;\n}\n","/**\n * Forma Reactive - Resource\n *\n * Async data fetching primitive with reactive loading/error state.\n * Tracks a source signal and refetches when it changes.\n *\n * SolidJS equivalent: createResource\n * React equivalent: use() + Suspense (React 19), or useSWR/react-query\n */\n\nimport { createSignal, type SignalGetter } from './signal.js';\nimport { internalEffect } from './effect.js';\nimport { untrack } from './untrack.js';\nimport { getSuspenseContext } from './suspense-context.js';\n\nexport interface Resource<T> {\n /** The resolved data (or undefined while loading). */\n (): T | undefined;\n /** True while the fetcher is running. */\n loading: SignalGetter<boolean>;\n /** The error if the fetcher rejected (or undefined). */\n error: SignalGetter<unknown>;\n /** Manually refetch with the current source value. */\n refetch: () => void;\n /** Manually set the data (overrides fetcher result). */\n mutate: (value: T | undefined) => void;\n}\n\nexport interface ResourceOptions<T> {\n /** Initial value before first fetch resolves. */\n initialValue?: T;\n}\n\n/**\n * Create an async resource that fetches data reactively.\n *\n * When `source` changes, the fetcher re-runs automatically.\n * Provides reactive `loading` and `error` signals.\n *\n * ```ts\n * const [userId, setUserId] = createSignal(1);\n *\n * const user = createResource(\n * userId, // source signal\n * (id) => fetch(`/api/users/${id}`).then(r => r.json()), // fetcher\n * );\n *\n * internalEffect(() => {\n * if (user.loading()) console.log('Loading...');\n * else if (user.error()) console.log('Error:', user.error());\n * else console.log('User:', user());\n * });\n *\n * setUserId(2); // automatically refetches\n * ```\n *\n * Without a source signal (static fetch):\n * ```ts\n * const posts = createResource(\n * () => true, // constant source — fetches once\n * () => fetch('/api/posts').then(r => r.json()),\n * );\n * ```\n */\nexport function createResource<T, S = true>(\n source: SignalGetter<S>,\n fetcher: (source: S) => Promise<T>,\n options?: ResourceOptions<T>,\n): Resource<T> {\n const [data, setData] = createSignal<T | undefined>(options?.initialValue);\n const [loading, setLoading] = createSignal(false);\n const [error, setError] = createSignal<unknown>(undefined);\n\n // Capture the Suspense context at creation time (not at fetch time).\n // This is critical because the Suspense boundary pushes/pops its context\n // synchronously during children() execution.\n const suspenseCtx = getSuspenseContext();\n\n let abortController: AbortController | null = null;\n let fetchVersion = 0;\n\n const doFetch = () => {\n // Read source outside tracking to get current value\n const sourceValue = untrack(source);\n\n // Abort previous in-flight request\n if (abortController) {\n abortController.abort();\n }\n const controller = new AbortController();\n abortController = controller;\n\n const version = ++fetchVersion;\n const isLatest = () => version === fetchVersion;\n let suspensePending = false;\n\n // Notify Suspense boundary that a fetch has started\n if (suspenseCtx) {\n suspenseCtx.increment();\n suspensePending = true;\n }\n\n setLoading(true);\n setError(undefined);\n\n Promise.resolve(fetcher(sourceValue))\n .then((result) => {\n // Only apply if this is still the latest fetch and wasn't aborted.\n if (isLatest() && !controller.signal.aborted) {\n setData(() => result);\n }\n })\n .catch((err) => {\n if (isLatest() && !controller.signal.aborted) {\n // Ignore abort errors\n if (err?.name !== 'AbortError') {\n setError(err);\n }\n }\n })\n .finally(() => {\n if (suspensePending) suspenseCtx?.decrement();\n if (isLatest()) {\n setLoading(false);\n if (abortController === controller) {\n abortController = null; // Release controller for GC\n }\n }\n });\n };\n\n // Auto-fetch when source changes\n internalEffect(() => {\n source(); // track the source signal\n doFetch();\n });\n\n // Build the resource object\n const resource = (() => data()) as Resource<T>;\n resource.loading = loading;\n resource.error = error;\n resource.refetch = doFetch;\n resource.mutate = (value) => setData(() => value);\n\n return resource;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/reactive/signal.ts","../src/reactive/computed.ts"],"names":["prevSub","prev","createRawSignal","rawComputed"],"mappings":";;;AAkEA,SAAS,cAAA,CACP,CAAA,EACA,CAAA,EACA,MAAA,EACM;AACN,EAAA,IAAI,OAAO,MAAM,UAAA,EAAY;AAC3B,IAAA,IAAI,MAAA,EAAQ;AAEV,MAAA,MAAMA,QAAAA,GAAU,aAAa,MAAS,CAAA;AACtC,MAAA,MAAMC,QAAO,CAAA,EAAE;AACf,MAAA,YAAA,CAAaD,QAAO,CAAA;AACpB,MAAA,IAAI,MAAA,CAAOC,KAAAA,EAAM,CAAC,CAAA,EAAG;AAAA,IACvB;AACA,IAAA,CAAA,CAAE,CAAC,CAAA;AACH,IAAA;AAAA,EACF;AAGA,EAAA,MAAM,OAAA,GAAU,aAAa,MAAS,CAAA;AACtC,EAAA,MAAM,OAAO,CAAA,EAAE;AACf,EAAA,YAAA,CAAa,OAAO,CAAA;AACpB,EAAA,MAAM,IAAA,GAAQ,EAAqB,IAAI,CAAA;AACvC,EAAA,IAAI,MAAA,IAAU,MAAA,CAAO,IAAA,EAAM,IAAI,CAAA,EAAG;AAClC,EAAA,CAAA,CAAE,IAAI,CAAA;AACR;AAqBO,SAAS,YAAA,CAAgB,cAAiB,OAAA,EAA0E;AACzH,EAAA,MAAM,CAAA,GAAIC,OAAmB,YAAY,CAAA;AACzC,EAAA,MAAM,MAAA,GAAS,CAAA;AACf,EAAA,MAAM,KAAK,OAAA,EAAS,MAAA;AACpB,EAAA,MAAM,SAA0B,CAAC,CAAA,KAA4B,cAAA,CAAe,CAAA,EAAG,GAAG,EAAE,CAAA;AAEpF,EAAA,OAAO,CAAC,QAAQ,MAAM,CAAA;AACxB;AC7EO,SAAS,eAAkB,EAAA,EAAuC;AACvE,EAAA,OAAOC,SAAY,EAAE,CAAA;AACvB","file":"chunk-OZCHIVAZ.js","sourcesContent":["/**\n * Forma Reactive - Signal\n *\n * Fine-grained reactive primitive backed by alien-signals.\n * API: createSignal returns [getter, setter] tuple following SolidJS conventions.\n *\n * TC39 Signals equivalent: Signal.State\n */\n\nimport { signal as createRawSignal, setActiveSub } from 'alien-signals';\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport type SignalGetter<T> = () => T;\nexport type SignalSetter<T> = (v: T | ((prev: T) => T)) => void;\n\nexport interface SignalOptions<T> {\n /** Debug name — attached to getter in dev mode for devtools inspection. */\n name?: string;\n /**\n * Custom equality check. When provided, the setter will read the current\n * value and only update the signal if `equals(prev, next)` returns `false`.\n *\n * Default: none (alien-signals uses strict inequality `!==` internally).\n *\n * ```ts\n * const [pos, setPos] = createSignal(\n * { x: 0, y: 0 },\n * { equals: (a, b) => a.x === b.x && a.y === b.y },\n * );\n *\n * setPos({ x: 0, y: 0 }); // skipped — equals returns true\n * setPos({ x: 1, y: 0 }); // applied — equals returns false\n * ```\n */\n equals?: (prev: T, next: T) => boolean;\n}\n\n/**\n * Wrap a value so the setter treats it as a literal value, not a functional updater.\n *\n * When `T` is itself a function type, passing a function to the setter is\n * ambiguous -- it looks like a functional update (`prev => next`). Use\n * `value()` to disambiguate:\n *\n * ```ts\n * const [getFn, setFn] = createSignal<() => void>(() => console.log('a'));\n *\n * // BUG: interpreted as a functional update -- calls the arrow with prev\n * // setFn(() => console.log('b'));\n *\n * // Correct: wraps in a thunk so the setter stores it as-is\n * setFn(value(() => console.log('b')));\n * ```\n */\nexport function value<T>(v: T): () => T {\n return () => v;\n}\n\ntype RawSignal<T> = {\n (): T;\n (value: T): void;\n};\n\nfunction applySignalSet<T>(\n s: RawSignal<T>,\n v: T | ((prev: T) => T),\n equals?: (prev: T, next: T) => boolean,\n): void {\n if (typeof v !== 'function') {\n if (equals) {\n // Read current value without tracking\n const prevSub = setActiveSub(undefined);\n const prev = s();\n setActiveSub(prevSub);\n if (equals(prev, v)) return; // skip — values are equal\n }\n s(v);\n return;\n }\n\n // Functional update: read prev without tracking\n const prevSub = setActiveSub(undefined);\n const prev = s();\n setActiveSub(prevSub);\n const next = (v as (prev: T) => T)(prev);\n if (equals && equals(prev, next)) return; // skip — values are equal\n s(next);\n}\n\n/**\n * Create a reactive signal.\n *\n * ```ts\n * const [count, setCount] = createSignal(0);\n * console.log(count()); // 0\n * setCount(1);\n * setCount(prev => prev + 1);\n * ```\n *\n * With custom equality:\n *\n * ```ts\n * const [pos, setPos] = createSignal(\n * { x: 0, y: 0 },\n * { equals: (a, b) => a.x === b.x && a.y === b.y },\n * );\n * ```\n */\nexport function createSignal<T>(initialValue: T, options?: SignalOptions<T>): [get: SignalGetter<T>, set: SignalSetter<T>] {\n const s = createRawSignal<T>(initialValue) as RawSignal<T>;\n const getter = s as unknown as SignalGetter<T>;\n const eq = options?.equals;\n const setter: SignalSetter<T> = (v: T | ((prev: T) => T)) => applySignalSet(s, v, eq);\n\n return [getter, setter];\n}\n","/**\n * Forma Reactive - Computed\n *\n * Lazy, cached derived value that participates in the reactive graph.\n * Backed by alien-signals for automatic dependency tracking\n * and cache invalidation.\n *\n * TC39 Signals equivalent: Signal.Computed\n */\n\nimport { computed as rawComputed } from 'alien-signals';\n\n/**\n * Create a lazy, cached computed value.\n *\n * Note: Unlike SolidJS's createComputed (which is an eager synchronous\n * side effect), this is a lazy cached derivation — equivalent to\n * SolidJS's createMemo. Both createComputed and createMemo in FormaJS\n * are identical.\n *\n * The getter receives the previous value as an argument, enabling\n * efficient diffing patterns without a separate signal:\n *\n * ```ts\n * const [count, setCount] = createSignal(0);\n * const doubled = createComputed(() => count() * 2);\n * console.log(doubled()); // 0\n * setCount(5);\n * console.log(doubled()); // 10\n * ```\n *\n * With previous value (for diffing):\n *\n * ```ts\n * const changes = createComputed((prev) => {\n * const next = items();\n * if (prev) console.log(`changed from ${prev.length} to ${next.length} items`);\n * return next;\n * });\n * ```\n */\nexport function createComputed<T>(fn: (previousValue?: T) => T): () => T {\n return rawComputed(fn);\n}\n"]}