@getforma/core 1.0.10 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/{chunk-6FW5E54W.cjs → chunk-2Y5US35K.cjs} +127 -103
  2. package/dist/chunk-2Y5US35K.cjs.map +1 -0
  3. package/dist/{chunk-3G7ET4O5.js → chunk-INNOI6TG.js} +121 -94
  4. package/dist/chunk-INNOI6TG.js.map +1 -0
  5. package/dist/{chunk-T33QUD2Y.cjs → chunk-JRQNDXX7.cjs} +43 -43
  6. package/dist/{chunk-T33QUD2Y.cjs.map → chunk-JRQNDXX7.cjs.map} +1 -1
  7. package/dist/{chunk-AFRFF7XL.js → chunk-MIOMT2CB.js} +4 -4
  8. package/dist/{chunk-AFRFF7XL.js.map → chunk-MIOMT2CB.js.map} +1 -1
  9. package/dist/chunk-W7OUWVRA.cjs +106 -0
  10. package/dist/chunk-W7OUWVRA.cjs.map +1 -0
  11. package/dist/chunk-XLVBYXOU.js +100 -0
  12. package/dist/chunk-XLVBYXOU.js.map +1 -0
  13. package/dist/forma-runtime-csp.js +52 -4
  14. package/dist/forma-runtime.js +98 -10
  15. package/dist/formajs-runtime-hardened.global.js +52 -4
  16. package/dist/formajs-runtime-hardened.global.js.map +1 -1
  17. package/dist/formajs-runtime.global.js +98 -10
  18. package/dist/formajs-runtime.global.js.map +1 -1
  19. package/dist/formajs.global.js +192 -95
  20. package/dist/formajs.global.js.map +1 -1
  21. package/dist/http.cjs +11 -11
  22. package/dist/http.js +2 -2
  23. package/dist/index.cjs +66 -66
  24. package/dist/index.d.cts +11 -25
  25. package/dist/index.d.ts +11 -25
  26. package/dist/index.js +6 -6
  27. package/dist/{resource-DeEzxUz6.d.cts → resource-D6HfVgiA.d.cts} +7 -2
  28. package/dist/{resource-BHsgURy0.d.ts → resource-ljs2X5NM.d.ts} +7 -2
  29. package/dist/runtime-hardened.cjs +53 -3
  30. package/dist/runtime-hardened.cjs.map +1 -1
  31. package/dist/runtime-hardened.js +53 -3
  32. package/dist/runtime-hardened.js.map +1 -1
  33. package/dist/runtime.cjs +29 -29
  34. package/dist/runtime.js +3 -3
  35. package/dist/server.cjs +7 -7
  36. package/dist/server.d.cts +2 -2
  37. package/dist/server.d.ts +2 -2
  38. package/dist/server.js +2 -2
  39. package/dist/{signal-C9v4akyJ.d.cts → signal-CRBJYQ6B.d.cts} +0 -8
  40. package/dist/{signal-C9v4akyJ.d.ts → signal-CRBJYQ6B.d.ts} +0 -8
  41. package/dist/tc39-compat.cjs +3 -6
  42. package/dist/tc39-compat.cjs.map +1 -1
  43. package/dist/tc39-compat.d.cts +1 -1
  44. package/dist/tc39-compat.d.ts +1 -1
  45. package/dist/tc39-compat.js +1 -4
  46. package/dist/tc39-compat.js.map +1 -1
  47. package/package.json +1 -1
  48. package/dist/chunk-3G7ET4O5.js.map +0 -1
  49. package/dist/chunk-6FW5E54W.cjs.map +0 -1
  50. package/dist/chunk-HLM5BZZQ.js +0 -35
  51. package/dist/chunk-HLM5BZZQ.js.map +0 -1
  52. package/dist/chunk-QLPCVK7C.cjs +0 -38
  53. package/dist/chunk-QLPCVK7C.cjs.map +0 -1
package/dist/runtime.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var chunkT33QUD2Y_cjs = require('./chunk-T33QUD2Y.cjs');
3
+ var chunkJRQNDXX7_cjs = require('./chunk-JRQNDXX7.cjs');
4
4
  var chunk263HW3KN_cjs = require('./chunk-263HW3KN.cjs');
5
- var chunk6FW5E54W_cjs = require('./chunk-6FW5E54W.cjs');
6
- var chunkQLPCVK7C_cjs = require('./chunk-QLPCVK7C.cjs');
5
+ var chunk2Y5US35K_cjs = require('./chunk-2Y5US35K.cjs');
6
+ var chunkW7OUWVRA_cjs = require('./chunk-W7OUWVRA.cjs');
7
7
 
8
8
  // src/dom/reconcile.ts
9
9
  function getBindTargets(el) {
@@ -974,7 +974,7 @@ function parseIfHandler(expr, scope) {
974
974
  }
975
975
  if (rest.length > 0) return null;
976
976
  return (e) => {
977
- chunk6FW5E54W_cjs.batch(() => {
977
+ chunk2Y5US35K_cjs.batch(() => {
978
978
  if (condExpr()) thenHandler(e);
979
979
  else elseHandler?.(e);
980
980
  });
@@ -1728,7 +1728,7 @@ function parseHandler(expr, scope) {
1728
1728
  const handlers = stmts.map((s) => parseHandler(s, scope));
1729
1729
  if (handlers.every((h) => h !== null)) {
1730
1730
  return (e) => {
1731
- chunk6FW5E54W_cjs.batch(() => {
1731
+ chunk2Y5US35K_cjs.batch(() => {
1732
1732
  for (const h of handlers) h(e);
1733
1733
  });
1734
1734
  };
@@ -1741,7 +1741,7 @@ function parseHandler(expr, scope) {
1741
1741
  const name = incrMatch[1];
1742
1742
  const op = incrMatch[2];
1743
1743
  return () => {
1744
- chunk6FW5E54W_cjs.batch(() => {
1744
+ chunk2Y5US35K_cjs.batch(() => {
1745
1745
  const val = scope.getters[name]?.() ?? 0;
1746
1746
  scope.setters[name]?.(op === "++" ? val + 1 : val - 1);
1747
1747
  });
@@ -1752,7 +1752,7 @@ function parseHandler(expr, scope) {
1752
1752
  const op = preIncrMatch[1];
1753
1753
  const name = preIncrMatch[2];
1754
1754
  return () => {
1755
- chunk6FW5E54W_cjs.batch(() => {
1755
+ chunk2Y5US35K_cjs.batch(() => {
1756
1756
  const val = scope.getters[name]?.() ?? 0;
1757
1757
  scope.setters[name]?.(op === "++" ? val + 1 : val - 1);
1758
1758
  });
@@ -1762,7 +1762,7 @@ function parseHandler(expr, scope) {
1762
1762
  if (toggleMatch && toggleMatch[1] === toggleMatch[2]) {
1763
1763
  const name = toggleMatch[1];
1764
1764
  return () => {
1765
- chunk6FW5E54W_cjs.batch(() => {
1765
+ chunk2Y5US35K_cjs.batch(() => {
1766
1766
  scope.setters[name]?.(!scope.getters[name]?.());
1767
1767
  });
1768
1768
  };
@@ -1774,7 +1774,7 @@ function parseHandler(expr, scope) {
1774
1774
  if (valExpr) {
1775
1775
  if (_debug) dbg(`parseHandler: assignment "${name} = ..." \u2014 setter exists:`, !!scope.setters[name], ", getter exists:", !!scope.getters[name]);
1776
1776
  return () => {
1777
- chunk6FW5E54W_cjs.batch(() => {
1777
+ chunk2Y5US35K_cjs.batch(() => {
1778
1778
  const val = valExpr();
1779
1779
  if (_debug) dbg(`SETTER: ${name} = ${val} (was: ${scope.getters[name]?.()})`);
1780
1780
  scope.setters[name]?.(val);
@@ -1789,7 +1789,7 @@ function parseHandler(expr, scope) {
1789
1789
  const valExpr = parseExpression(compoundMatch[3].trim(), scope);
1790
1790
  if (valExpr) {
1791
1791
  return () => {
1792
- chunk6FW5E54W_cjs.batch(() => {
1792
+ chunk2Y5US35K_cjs.batch(() => {
1793
1793
  const current = scope.getters[name]?.() ?? 0;
1794
1794
  const val = valExpr();
1795
1795
  switch (op) {
@@ -1870,7 +1870,7 @@ function buildHandler(expr, scope) {
1870
1870
  }
1871
1871
  });
1872
1872
  const unsafeHandler = (e) => {
1873
- chunk6FW5E54W_cjs.batch(() => fn(proxy, e, e));
1873
+ chunk2Y5US35K_cjs.batch(() => fn(proxy, e, e));
1874
1874
  };
1875
1875
  const result = {
1876
1876
  handler: unsafeHandler,
@@ -1918,7 +1918,7 @@ function initScope(stateEl) {
1918
1918
  const getters = {};
1919
1919
  const setters = {};
1920
1920
  for (const [key, initial] of Object.entries(state)) {
1921
- const [get, set] = chunkQLPCVK7C_cjs.createSignal(initial);
1921
+ const [get, set] = chunkW7OUWVRA_cjs.createSignal(initial);
1922
1922
  getters[key] = get;
1923
1923
  setters[key] = set;
1924
1924
  }
@@ -2030,7 +2030,7 @@ function bindElement(el, scope, disposers) {
2030
2030
  const prevGetter = scope.getters[name];
2031
2031
  delete scope.getters[name];
2032
2032
  const evaluate = buildEvaluator(`{${expr}}`, scope);
2033
- const getter = chunkQLPCVK7C_cjs.createComputed(evaluate);
2033
+ const getter = chunkW7OUWVRA_cjs.createComputed(evaluate);
2034
2034
  scope.getters[name] = getter;
2035
2035
  if (!prevGetter) {
2036
2036
  delete scope.setters[name];
@@ -2041,7 +2041,7 @@ function bindElement(el, scope, disposers) {
2041
2041
  const textExpr = !known || known.has("data-text") ? el.getAttribute("data-text") : null;
2042
2042
  if (textExpr) {
2043
2043
  const evaluate = buildEvaluator(textExpr, scope);
2044
- const dispose = chunk6FW5E54W_cjs.internalEffect(() => {
2044
+ const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2045
2045
  setElementTextFast(el, toTextValue(evaluate()));
2046
2046
  });
2047
2047
  disposers.push(dispose);
@@ -2056,7 +2056,7 @@ function bindElement(el, scope, disposers) {
2056
2056
  dbg(`bindElement: data-show="${showExpr}" on <${tag}${cls}>`);
2057
2057
  }
2058
2058
  let initialized = false;
2059
- const dispose = chunk6FW5E54W_cjs.internalEffect(() => {
2059
+ const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2060
2060
  const visible = !!evaluate();
2061
2061
  if (_debug) dbg(`data-show effect: "${showExpr}" \u2192 ${visible}`);
2062
2062
  applyShowVisibility(el, visible, transition, !initialized);
@@ -2075,7 +2075,7 @@ function bindElement(el, scope, disposers) {
2075
2075
  const parent = el.parentNode;
2076
2076
  let inserted = true;
2077
2077
  let initialized = false;
2078
- const dispose = chunk6FW5E54W_cjs.internalEffect(() => {
2078
+ const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2079
2079
  const show = !!evaluate();
2080
2080
  if (show && !inserted) {
2081
2081
  clearTransitionState(el);
@@ -2114,7 +2114,7 @@ function bindElement(el, scope, disposers) {
2114
2114
  const setter = scope.setters[prop];
2115
2115
  if (getter && setter) {
2116
2116
  const input = el;
2117
- const dispose = chunk6FW5E54W_cjs.internalEffect(() => {
2117
+ const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2118
2118
  const val = getter();
2119
2119
  if (input.type === "checkbox") {
2120
2120
  input.checked = !!val;
@@ -2178,14 +2178,14 @@ function bindElement(el, scope, disposers) {
2178
2178
  } else if (name.startsWith("data-class:")) {
2179
2179
  const cls = name.slice(11);
2180
2180
  const evaluate = buildEvaluator(attr.value, scope);
2181
- const dispose = chunk6FW5E54W_cjs.internalEffect(() => {
2181
+ const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2182
2182
  el.classList.toggle(cls, !!evaluate());
2183
2183
  });
2184
2184
  disposers.push(dispose);
2185
2185
  } else if (name.startsWith("data-bind:")) {
2186
2186
  const attrName = name.slice(10);
2187
2187
  const evaluate = buildEvaluator(attr.value, scope);
2188
- const dispose = chunk6FW5E54W_cjs.internalEffect(() => {
2188
+ const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2189
2189
  const val = evaluate();
2190
2190
  if (val == null || val === false) {
2191
2191
  el.removeAttribute(attrName);
@@ -2213,7 +2213,7 @@ function bindElement(el, scope, disposers) {
2213
2213
  if (saved !== null) setter(JSON.parse(saved));
2214
2214
  } catch {
2215
2215
  }
2216
- const dispose = chunk6FW5E54W_cjs.internalEffect(() => {
2216
+ const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2217
2217
  try {
2218
2218
  localStorage.setItem(key, JSON.stringify(getter()));
2219
2219
  } catch {
@@ -2300,7 +2300,7 @@ function bindElement(el, scope, disposers) {
2300
2300
  });
2301
2301
  }
2302
2302
  } : void 0;
2303
- const dispose = chunk6FW5E54W_cjs.internalEffect(() => {
2303
+ const dispose = chunk2Y5US35K_cjs.internalEffect(() => {
2304
2304
  const rawItems = evaluate();
2305
2305
  if (!Array.isArray(rawItems)) {
2306
2306
  for (const n of oldNodes) {
@@ -2321,7 +2321,7 @@ function bindElement(el, scope, disposers) {
2321
2321
  }
2322
2322
  const prevNodes = new Set(oldNodes);
2323
2323
  if (keyProp) {
2324
- const result = chunkT33QUD2Y_cjs.reconcileList(
2324
+ const result = chunkJRQNDXX7_cjs.reconcileList(
2325
2325
  el,
2326
2326
  oldItems,
2327
2327
  rawItems,
@@ -2351,7 +2351,7 @@ function bindElement(el, scope, disposers) {
2351
2351
  } else {
2352
2352
  const wrapped = rawItems.map((item, i) => ({ __idx: i, __item: item }));
2353
2353
  const oldWrapped = oldItems;
2354
- const result = chunkT33QUD2Y_cjs.reconcileList(
2354
+ const result = chunkJRQNDXX7_cjs.reconcileList(
2355
2355
  el,
2356
2356
  oldWrapped,
2357
2357
  wrapped,
@@ -2400,16 +2400,16 @@ function bindElement(el, scope, disposers) {
2400
2400
  else if (k === "error") errorTarget = v;
2401
2401
  else if (k === "poll") interval = parseInt(v ?? "0", 10);
2402
2402
  }
2403
- const [getTarget, setTarget] = chunkQLPCVK7C_cjs.createSignal(null);
2403
+ const [getTarget, setTarget] = chunkW7OUWVRA_cjs.createSignal(null);
2404
2404
  scope.getters[target] = getTarget;
2405
2405
  scope.setters[target] = setTarget;
2406
2406
  if (loadingTarget) {
2407
- const [gl, sl] = chunkQLPCVK7C_cjs.createSignal(false);
2407
+ const [gl, sl] = chunkW7OUWVRA_cjs.createSignal(false);
2408
2408
  scope.getters[loadingTarget] = gl;
2409
2409
  scope.setters[loadingTarget] = sl;
2410
2410
  }
2411
2411
  if (errorTarget) {
2412
- const [ge, se] = chunkQLPCVK7C_cjs.createSignal(null);
2412
+ const [ge, se] = chunkW7OUWVRA_cjs.createSignal(null);
2413
2413
  scope.getters[errorTarget] = ge;
2414
2414
  scope.setters[errorTarget] = se;
2415
2415
  }
@@ -2738,7 +2738,7 @@ function getScopes() {
2738
2738
  function setScopeValue(element, key, value) {
2739
2739
  const scope = element.__formaScope;
2740
2740
  if (!scope?.setters[key]) return;
2741
- chunk6FW5E54W_cjs.batch(() => {
2741
+ chunk2Y5US35K_cjs.batch(() => {
2742
2742
  scope.setters[key](value);
2743
2743
  });
2744
2744
  }
@@ -2747,7 +2747,7 @@ function resetScope(element) {
2747
2747
  const initialJSON = element.__formaInitialState;
2748
2748
  if (!scope || !initialJSON) return;
2749
2749
  const initial = parseState(initialJSON);
2750
- chunk6FW5E54W_cjs.batch(() => {
2750
+ chunk2Y5US35K_cjs.batch(() => {
2751
2751
  for (const [key, val] of Object.entries(initial)) {
2752
2752
  scope.setters[key]?.(val);
2753
2753
  }
@@ -2777,7 +2777,7 @@ function getReconciler() {
2777
2777
  }
2778
2778
  }
2779
2779
  },
2780
- batch: chunk6FW5E54W_cjs.batch
2780
+ batch: chunk2Y5US35K_cjs.batch
2781
2781
  });
2782
2782
  }
2783
2783
  return _reconciler;
package/dist/runtime.js CHANGED
@@ -1,7 +1,7 @@
1
- import { reconcileList } from './chunk-AFRFF7XL.js';
1
+ import { reconcileList } from './chunk-MIOMT2CB.js';
2
2
  import { isEventHandlerAttr, isUrlAttr, isDangerousUrl } from './chunk-2QQBKQIF.js';
3
- import { internalEffect, batch } from './chunk-3G7ET4O5.js';
4
- import { createSignal, createComputed } from './chunk-HLM5BZZQ.js';
3
+ import { internalEffect, batch } from './chunk-INNOI6TG.js';
4
+ import { createSignal, createComputed } from './chunk-XLVBYXOU.js';
5
5
 
6
6
  // src/dom/reconcile.ts
7
7
  function getBindTargets(el) {
package/dist/server.cjs CHANGED
@@ -1,25 +1,25 @@
1
1
  'use strict';
2
2
 
3
- var chunk6FW5E54W_cjs = require('./chunk-6FW5E54W.cjs');
4
- var chunkQLPCVK7C_cjs = require('./chunk-QLPCVK7C.cjs');
3
+ var chunk2Y5US35K_cjs = require('./chunk-2Y5US35K.cjs');
4
+ var chunkW7OUWVRA_cjs = require('./chunk-W7OUWVRA.cjs');
5
5
 
6
6
  // src/server/action.ts
7
7
  function createAction(serverFn, options) {
8
- const [pending, setPending] = chunkQLPCVK7C_cjs.createSignal(false);
9
- const [error, setError] = chunkQLPCVK7C_cjs.createSignal(void 0);
8
+ const [pending, setPending] = chunkW7OUWVRA_cjs.createSignal(false);
9
+ const [error, setError] = chunkW7OUWVRA_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
- chunk6FW5E54W_cjs.batch(() => options.optimistic(...args));
15
+ chunk2Y5US35K_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
- chunk6FW5E54W_cjs.batch(() => options.onSuccess(result, ...args));
22
+ chunk2Y5US35K_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
- chunk6FW5E54W_cjs.batch(() => options.onError(err, ...args));
34
+ chunk2Y5US35K_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-DeEzxUz6.cjs';
2
- import './signal-C9v4akyJ.cjs';
1
+ import { R as Resource } from './resource-D6HfVgiA.cjs';
2
+ import './signal-CRBJYQ6B.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-BHsgURy0.js';
2
- import './signal-C9v4akyJ.js';
1
+ import { R as Resource } from './resource-ljs2X5NM.js';
2
+ import './signal-CRBJYQ6B.js';
3
3
 
4
4
  /**
5
5
  * FormaJS Server - Action
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
- import { batch } from './chunk-3G7ET4O5.js';
2
- import { createSignal } from './chunk-HLM5BZZQ.js';
1
+ import { batch } from './chunk-INNOI6TG.js';
2
+ import { createSignal } from './chunk-XLVBYXOU.js';
3
3
 
4
4
  // src/server/action.ts
5
5
  function createAction(serverFn, options) {
@@ -1,11 +1,3 @@
1
- /**
2
- * Forma Reactive - Signal
3
- *
4
- * Fine-grained reactive primitive backed by alien-signals.
5
- * API: createSignal returns [getter, setter] tuple following SolidJS conventions.
6
- *
7
- * TC39 Signals equivalent: Signal.State
8
- */
9
1
  /** A function that reads the current value of a signal. */
10
2
  type SignalGetter<T> = () => T;
11
3
  /** A function that updates a signal — accepts a value or an updater function. */
@@ -1,11 +1,3 @@
1
- /**
2
- * Forma Reactive - Signal
3
- *
4
- * Fine-grained reactive primitive backed by alien-signals.
5
- * API: createSignal returns [getter, setter] tuple following SolidJS conventions.
6
- *
7
- * TC39 Signals equivalent: Signal.State
8
- */
9
1
  /** A function that reads the current value of a signal. */
10
2
  type SignalGetter<T> = () => T;
11
3
  /** A function that updates a signal — accepts a value or an updater function. */
@@ -1,18 +1,15 @@
1
1
  'use strict';
2
2
 
3
- var chunkQLPCVK7C_cjs = require('./chunk-QLPCVK7C.cjs');
3
+ var chunkW7OUWVRA_cjs = require('./chunk-W7OUWVRA.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] = chunkQLPCVK7C_cjs.createSignal(initialValue, options);
10
+ const [getter, setter] = chunkW7OUWVRA_cjs.createSignal(initialValue, options);
11
11
  this._get = getter;
12
12
  this._set = setter;
13
- if (options?.name) {
14
- Object.defineProperty(getter, "name", { value: options.name });
15
- }
16
13
  }
17
14
  get() {
18
15
  return this._get();
@@ -24,7 +21,7 @@ var State = class {
24
21
  var Computed = class {
25
22
  _get;
26
23
  constructor(fn) {
27
- this._get = chunkQLPCVK7C_cjs.createComputed(fn);
24
+ this._get = chunkW7OUWVRA_cjs.createComputed(fn);
28
25
  }
29
26
  get() {
30
27
  return this._get();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/reactive/tc39-compat.ts"],"names":["createSignal","createComputed"],"mappings":";;;;;AAyBO,IAAM,QAAN,MAAe;AAAA,EACZ,IAAA;AAAA,EACA,IAAA;AAAA,EAER,WAAA,CAAY,cAAiB,OAAA,EAA4B;AAEvD,IAAA,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,GAAIA,8BAAA,CAAa,cAAc,OAAO,CAAA;AAC3D,IAAA,IAAA,CAAK,IAAA,GAAO,MAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,MAAA;AAEZ,IAAA,IAAI,SAAS,IAAA,EAAM;AACjB,MAAA,MAAA,CAAO,eAAe,MAAA,EAAQ,MAAA,EAAQ,EAAE,KAAA,EAAO,OAAA,CAAQ,MAAM,CAAA;AAAA,IAC/D;AAAA,EACF;AAAA,EAEA,GAAA,GAAS;AACP,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB;AAAA,EAEA,IAAI,KAAA,EAAgB;AAClB,IAAA,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,EACjB;AACF;AAcO,IAAM,WAAN,MAAkB;AAAA,EACf,IAAA;AAAA,EAER,YAAY,EAAA,EAAa;AACvB,IAAA,IAAA,CAAK,IAAA,GAAOC,iCAAe,EAAE,CAAA;AAAA,EAC/B;AAAA,EAEA,GAAA,GAAS;AACP,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB;AACF","file":"tc39-compat.cjs","sourcesContent":["/**\n * Forma Reactive - TC39 Signals Compatibility Layer\n *\n * Optional class-based API matching the TC39 Signals proposal (Stage 1).\n * Not included in main bundle — import from '@getforma/core/tc39' subpath.\n *\n * When the TC39 proposal advances, these classes can be replaced with\n * native Signal.State and Signal.Computed.\n *\n * @see https://github.com/tc39/proposal-signals\n */\n\nimport { createSignal, type SignalOptions } from './signal.js';\nimport { createComputed } from './computed.js';\n\n/**\n * TC39-compatible reactive state container.\n * Equivalent to `Signal.State` in the TC39 proposal.\n *\n * ```ts\n * const count = new State(0);\n * console.log(count.get()); // 0\n * count.set(1);\n * ```\n */\nexport class State<T> {\n private _get: () => T;\n private _set: (v: T | ((prev: T) => T)) => void;\n\n constructor(initialValue: T, options?: SignalOptions<T>) {\n // createSignal now natively supports equals — pass options through\n const [getter, setter] = createSignal(initialValue, options);\n this._get = getter;\n this._set = setter;\n\n if (options?.name) {\n Object.defineProperty(getter, 'name', { value: options.name });\n }\n }\n\n get(): T {\n return this._get();\n }\n\n set(value: T): void {\n this._set(value);\n }\n}\n\n/**\n * TC39-compatible computed value.\n * Equivalent to `Signal.Computed` in the TC39 proposal.\n *\n * ```ts\n * const count = new State(0);\n * const doubled = new Computed(() => count.get() * 2);\n * console.log(doubled.get()); // 0\n * count.set(5);\n * console.log(doubled.get()); // 10\n * ```\n */\nexport class Computed<T> {\n private _get: () => T;\n\n constructor(fn: () => T) {\n this._get = createComputed(fn);\n }\n\n get(): T {\n return this._get();\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/reactive/tc39-compat.ts"],"names":["createSignal","createComputed"],"mappings":";;;;;AAyBO,IAAM,QAAN,MAAe;AAAA,EACZ,IAAA;AAAA,EACA,IAAA;AAAA,EAER,WAAA,CAAY,cAAiB,OAAA,EAA4B;AAGvD,IAAA,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,GAAIA,8BAAA,CAAa,cAAc,OAAO,CAAA;AAC3D,IAAA,IAAA,CAAK,IAAA,GAAO,MAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,MAAA;AAAA,EACd;AAAA,EAEA,GAAA,GAAS;AACP,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB;AAAA,EAEA,IAAI,KAAA,EAAgB;AAClB,IAAA,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,EACjB;AACF;AAcO,IAAM,WAAN,MAAkB;AAAA,EACf,IAAA;AAAA,EAER,YAAY,EAAA,EAAa;AACvB,IAAA,IAAA,CAAK,IAAA,GAAOC,iCAAe,EAAE,CAAA;AAAA,EAC/B;AAAA,EAEA,GAAA,GAAS;AACP,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB;AACF","file":"tc39-compat.cjs","sourcesContent":["/**\n * Forma Reactive - TC39 Signals Compatibility Layer\n *\n * Optional class-based API matching the TC39 Signals proposal (Stage 1).\n * Not included in main bundle — import from '@getforma/core/tc39' subpath.\n *\n * When the TC39 proposal advances, these classes can be replaced with\n * native Signal.State and Signal.Computed.\n *\n * @see https://github.com/tc39/proposal-signals\n */\n\nimport { createSignal, type SignalOptions } from './signal.js';\nimport { createComputed } from './computed.js';\n\n/**\n * TC39-compatible reactive state container.\n * Equivalent to `Signal.State` in the TC39 proposal.\n *\n * ```ts\n * const count = new State(0);\n * console.log(count.get()); // 0\n * count.set(1);\n * ```\n */\nexport class State<T> {\n private _get: () => T;\n private _set: (v: T | ((prev: T) => T)) => void;\n\n constructor(initialValue: T, options?: SignalOptions<T>) {\n // createSignal natively supports equals and the debug name (stored in a side\n // table so isSignal() keeps recognizing the getter) — pass options through.\n const [getter, setter] = createSignal(initialValue, options);\n this._get = getter;\n this._set = setter;\n }\n\n get(): T {\n return this._get();\n }\n\n set(value: T): void {\n this._set(value);\n }\n}\n\n/**\n * TC39-compatible computed value.\n * Equivalent to `Signal.Computed` in the TC39 proposal.\n *\n * ```ts\n * const count = new State(0);\n * const doubled = new Computed(() => count.get() * 2);\n * console.log(doubled.get()); // 0\n * count.set(5);\n * console.log(doubled.get()); // 10\n * ```\n */\nexport class Computed<T> {\n private _get: () => T;\n\n constructor(fn: () => T) {\n this._get = createComputed(fn);\n }\n\n get(): T {\n return this._get();\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { a as SignalOptions } from './signal-C9v4akyJ.cjs';
1
+ import { a as SignalOptions } from './signal-CRBJYQ6B.cjs';
2
2
 
3
3
  /**
4
4
  * Forma Reactive - TC39 Signals Compatibility Layer
@@ -1,4 +1,4 @@
1
- import { a as SignalOptions } from './signal-C9v4akyJ.js';
1
+ import { a as SignalOptions } from './signal-CRBJYQ6B.js';
2
2
 
3
3
  /**
4
4
  * Forma Reactive - TC39 Signals Compatibility Layer
@@ -1,4 +1,4 @@
1
- import { createSignal, createComputed } from './chunk-HLM5BZZQ.js';
1
+ import { createSignal, createComputed } from './chunk-XLVBYXOU.js';
2
2
 
3
3
  // src/reactive/tc39-compat.ts
4
4
  var State = class {
@@ -8,9 +8,6 @@ var State = class {
8
8
  const [getter, setter] = createSignal(initialValue, options);
9
9
  this._get = getter;
10
10
  this._set = setter;
11
- if (options?.name) {
12
- Object.defineProperty(getter, "name", { value: options.name });
13
- }
14
11
  }
15
12
  get() {
16
13
  return this._get();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/reactive/tc39-compat.ts"],"names":[],"mappings":";;;AAyBO,IAAM,QAAN,MAAe;AAAA,EACZ,IAAA;AAAA,EACA,IAAA;AAAA,EAER,WAAA,CAAY,cAAiB,OAAA,EAA4B;AAEvD,IAAA,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,GAAI,YAAA,CAAa,cAAc,OAAO,CAAA;AAC3D,IAAA,IAAA,CAAK,IAAA,GAAO,MAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,MAAA;AAEZ,IAAA,IAAI,SAAS,IAAA,EAAM;AACjB,MAAA,MAAA,CAAO,eAAe,MAAA,EAAQ,MAAA,EAAQ,EAAE,KAAA,EAAO,OAAA,CAAQ,MAAM,CAAA;AAAA,IAC/D;AAAA,EACF;AAAA,EAEA,GAAA,GAAS;AACP,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB;AAAA,EAEA,IAAI,KAAA,EAAgB;AAClB,IAAA,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,EACjB;AACF;AAcO,IAAM,WAAN,MAAkB;AAAA,EACf,IAAA;AAAA,EAER,YAAY,EAAA,EAAa;AACvB,IAAA,IAAA,CAAK,IAAA,GAAO,eAAe,EAAE,CAAA;AAAA,EAC/B;AAAA,EAEA,GAAA,GAAS;AACP,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB;AACF","file":"tc39-compat.js","sourcesContent":["/**\n * Forma Reactive - TC39 Signals Compatibility Layer\n *\n * Optional class-based API matching the TC39 Signals proposal (Stage 1).\n * Not included in main bundle — import from '@getforma/core/tc39' subpath.\n *\n * When the TC39 proposal advances, these classes can be replaced with\n * native Signal.State and Signal.Computed.\n *\n * @see https://github.com/tc39/proposal-signals\n */\n\nimport { createSignal, type SignalOptions } from './signal.js';\nimport { createComputed } from './computed.js';\n\n/**\n * TC39-compatible reactive state container.\n * Equivalent to `Signal.State` in the TC39 proposal.\n *\n * ```ts\n * const count = new State(0);\n * console.log(count.get()); // 0\n * count.set(1);\n * ```\n */\nexport class State<T> {\n private _get: () => T;\n private _set: (v: T | ((prev: T) => T)) => void;\n\n constructor(initialValue: T, options?: SignalOptions<T>) {\n // createSignal now natively supports equals — pass options through\n const [getter, setter] = createSignal(initialValue, options);\n this._get = getter;\n this._set = setter;\n\n if (options?.name) {\n Object.defineProperty(getter, 'name', { value: options.name });\n }\n }\n\n get(): T {\n return this._get();\n }\n\n set(value: T): void {\n this._set(value);\n }\n}\n\n/**\n * TC39-compatible computed value.\n * Equivalent to `Signal.Computed` in the TC39 proposal.\n *\n * ```ts\n * const count = new State(0);\n * const doubled = new Computed(() => count.get() * 2);\n * console.log(doubled.get()); // 0\n * count.set(5);\n * console.log(doubled.get()); // 10\n * ```\n */\nexport class Computed<T> {\n private _get: () => T;\n\n constructor(fn: () => T) {\n this._get = createComputed(fn);\n }\n\n get(): T {\n return this._get();\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/reactive/tc39-compat.ts"],"names":[],"mappings":";;;AAyBO,IAAM,QAAN,MAAe;AAAA,EACZ,IAAA;AAAA,EACA,IAAA;AAAA,EAER,WAAA,CAAY,cAAiB,OAAA,EAA4B;AAGvD,IAAA,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,GAAI,YAAA,CAAa,cAAc,OAAO,CAAA;AAC3D,IAAA,IAAA,CAAK,IAAA,GAAO,MAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,MAAA;AAAA,EACd;AAAA,EAEA,GAAA,GAAS;AACP,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB;AAAA,EAEA,IAAI,KAAA,EAAgB;AAClB,IAAA,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,EACjB;AACF;AAcO,IAAM,WAAN,MAAkB;AAAA,EACf,IAAA;AAAA,EAER,YAAY,EAAA,EAAa;AACvB,IAAA,IAAA,CAAK,IAAA,GAAO,eAAe,EAAE,CAAA;AAAA,EAC/B;AAAA,EAEA,GAAA,GAAS;AACP,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB;AACF","file":"tc39-compat.js","sourcesContent":["/**\n * Forma Reactive - TC39 Signals Compatibility Layer\n *\n * Optional class-based API matching the TC39 Signals proposal (Stage 1).\n * Not included in main bundle — import from '@getforma/core/tc39' subpath.\n *\n * When the TC39 proposal advances, these classes can be replaced with\n * native Signal.State and Signal.Computed.\n *\n * @see https://github.com/tc39/proposal-signals\n */\n\nimport { createSignal, type SignalOptions } from './signal.js';\nimport { createComputed } from './computed.js';\n\n/**\n * TC39-compatible reactive state container.\n * Equivalent to `Signal.State` in the TC39 proposal.\n *\n * ```ts\n * const count = new State(0);\n * console.log(count.get()); // 0\n * count.set(1);\n * ```\n */\nexport class State<T> {\n private _get: () => T;\n private _set: (v: T | ((prev: T) => T)) => void;\n\n constructor(initialValue: T, options?: SignalOptions<T>) {\n // createSignal natively supports equals and the debug name (stored in a side\n // table so isSignal() keeps recognizing the getter) — pass options through.\n const [getter, setter] = createSignal(initialValue, options);\n this._get = getter;\n this._set = setter;\n }\n\n get(): T {\n return this._get();\n }\n\n set(value: T): void {\n this._set(value);\n }\n}\n\n/**\n * TC39-compatible computed value.\n * Equivalent to `Signal.Computed` in the TC39 proposal.\n *\n * ```ts\n * const count = new State(0);\n * const doubled = new Computed(() => count.get() * 2);\n * console.log(doubled.get()); // 0\n * count.set(5);\n * console.log(doubled.get()); // 10\n * ```\n */\nexport class Computed<T> {\n private _get: () => T;\n\n constructor(fn: () => T) {\n this._get = createComputed(fn);\n }\n\n get(): T {\n return this._get();\n }\n}\n"]}
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.10",
4
+ "version": "1.1.0",
5
5
  "description": "Real DOM reactive library — fine-grained signals, islands architecture, SSR hydration. No virtual DOM, no diffing. Core entry ~8KB gzipped; full HTML runtime ~24KB gzipped.",
6
6
  "type": "module",
7
7
  "main": "./dist/index.cjs",
@@ -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","setActiveSub","value"],"mappings":"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","file":"chunk-3G7ET4O5.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 * Roots created inside another root are automatically owned by the parent\n * (Solid-style). When the parent is disposed, all child roots are disposed\n * too. Use {@link createUnownedRoot} for roots that must outlive their\n * lexical parent (e.g., mount points, test harnesses).\n */\n\nimport { effectScope as rawEffectScope, setActiveSub } 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// Shared implementation\n// ---------------------------------------------------------------------------\n\nfunction createRootImpl<T>(fn: (dispose: () => void) => T, owned: boolean): T {\n const scope: RootScope = { disposers: [], scopeDispose: null };\n const parentRoot = owned ? currentRoot : null;\n\n rootStack.push(currentRoot);\n currentRoot = scope;\n\n let disposed = false;\n const dispose = () => {\n if (disposed) return; // idempotent — safe to call after parent already disposed this\n disposed = true;\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 (includes child root disposes)\n for (const d of scope.disposers) {\n try { d(); } catch { /* ensure all disposers run */ }\n }\n scope.disposers.length = 0;\n };\n\n // Auto-register with parent root so child dies when parent dies (Solid-style)\n if (parentRoot) {\n parentRoot.disposers.push(dispose);\n }\n\n let result: T;\n try {\n if (owned) {\n // Owned: alien-signals nesting is kept (belt + suspenders with Forma cascade)\n scope.scopeDispose = rawEffectScope(() => {\n result = fn(dispose);\n });\n } else {\n // Unowned: break alien-signals scope nesting so this scope is NOT\n // disposed when the lexical parent scope is disposed.\n const prevSub = setActiveSub(undefined);\n try {\n scope.scopeDispose = rawEffectScope(() => {\n result = fn(dispose);\n });\n } finally {\n setActiveSub(prevSub);\n }\n }\n } finally {\n currentRoot = rootStack.pop() ?? null;\n }\n\n return result!;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\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 * Roots created inside another root are automatically owned by the parent.\n * When the parent is disposed, this root is disposed too.\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 return createRootImpl(fn, true);\n}\n\n/**\n * Create a reactive root that is NOT owned by any parent root.\n *\n * Use this for roots that must outlive their lexical parent:\n * top-level mount points, island hydration, test harnesses, etc.\n *\n * ```ts\n * createRoot(() => {\n * // This root outlives the parent even though it's nested:\n * createUnownedRoot((dispose) => {\n * // effects here survive parent disposal\n * });\n * });\n * ```\n */\nexport function createUnownedRoot<T>(fn: (dispose: () => void) => T): T {\n return createRootImpl(fn, false);\n}\n\n/**\n * @internal — called by createEffect and DOM primitives to register disposers\n * 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\n/** Callback signature for the global {@link onError} handler. */\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\n/** A mutable container that does NOT trigger reactivity when written to. */\nexport interface Ref<T> {\n /** The stored value. Mutating this does not notify effects. */\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\n/** A function that dispatches an action to a reducer. */\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\n/** Context object for a Suspense boundary, tracking pending async resources. */\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\n/** An async data resource with reactive loading and error state. */\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\n/** Options for {@link createResource}. */\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"]}