@getforma/core 1.0.10 → 1.2.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 (55) hide show
  1. package/dist/{chunk-T33QUD2Y.cjs → chunk-E3FV2VSU.cjs} +43 -43
  2. package/dist/{chunk-T33QUD2Y.cjs.map → chunk-E3FV2VSU.cjs.map} +1 -1
  3. package/dist/chunk-ETPJTPYD.js +103 -0
  4. package/dist/chunk-ETPJTPYD.js.map +1 -0
  5. package/dist/chunk-H7MDUHS5.cjs +110 -0
  6. package/dist/chunk-H7MDUHS5.cjs.map +1 -0
  7. package/dist/{chunk-6FW5E54W.cjs → chunk-KUXNZ5MG.cjs} +127 -103
  8. package/dist/chunk-KUXNZ5MG.cjs.map +1 -0
  9. package/dist/{chunk-3G7ET4O5.js → chunk-Y3A2EVVS.js} +121 -94
  10. package/dist/chunk-Y3A2EVVS.js.map +1 -0
  11. package/dist/{chunk-AFRFF7XL.js → chunk-YRNYOZF3.js} +4 -4
  12. package/dist/{chunk-AFRFF7XL.js.map → chunk-YRNYOZF3.js.map} +1 -1
  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 +368 -147
  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 +262 -141
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +32 -27
  26. package/dist/index.d.ts +32 -27
  27. package/dist/index.js +204 -83
  28. package/dist/index.js.map +1 -1
  29. package/dist/{resource-DeEzxUz6.d.cts → resource-D6HfVgiA.d.cts} +7 -2
  30. package/dist/{resource-BHsgURy0.d.ts → resource-ljs2X5NM.d.ts} +7 -2
  31. package/dist/runtime-hardened.cjs +53 -3
  32. package/dist/runtime-hardened.cjs.map +1 -1
  33. package/dist/runtime-hardened.js +53 -3
  34. package/dist/runtime-hardened.js.map +1 -1
  35. package/dist/runtime.cjs +29 -29
  36. package/dist/runtime.js +3 -3
  37. package/dist/server.cjs +7 -7
  38. package/dist/server.d.cts +2 -2
  39. package/dist/server.d.ts +2 -2
  40. package/dist/server.js +2 -2
  41. package/dist/{signal-C9v4akyJ.d.cts → signal-CRBJYQ6B.d.cts} +0 -8
  42. package/dist/{signal-C9v4akyJ.d.ts → signal-CRBJYQ6B.d.ts} +0 -8
  43. package/dist/tc39-compat.cjs +3 -6
  44. package/dist/tc39-compat.cjs.map +1 -1
  45. package/dist/tc39-compat.d.cts +1 -1
  46. package/dist/tc39-compat.d.ts +1 -1
  47. package/dist/tc39-compat.js +1 -4
  48. package/dist/tc39-compat.js.map +1 -1
  49. package/package.json +1 -1
  50. package/dist/chunk-3G7ET4O5.js.map +0 -1
  51. package/dist/chunk-6FW5E54W.cjs.map +0 -1
  52. package/dist/chunk-HLM5BZZQ.js +0 -35
  53. package/dist/chunk-HLM5BZZQ.js.map +0 -1
  54. package/dist/chunk-QLPCVK7C.cjs +0 -38
  55. package/dist/chunk-QLPCVK7C.cjs.map +0 -1
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  /// <reference path="./jsx.d.ts" />
2
- import { S as SignalGetter } from './signal-C9v4akyJ.cjs';
3
- export { a as SignalOptions, b as SignalSetter, c as createSignal } from './signal-C9v4akyJ.cjs';
4
- export { R as Resource, a as ResourceOptions, c as createResource } from './resource-DeEzxUz6.cjs';
2
+ import { S as SignalGetter } from './signal-CRBJYQ6B.cjs';
3
+ export { a as SignalOptions, b as SignalSetter, c as createSignal } from './signal-CRBJYQ6B.cjs';
4
+ export { R as Resource, a as ResourceOptions, c as createResource } from './resource-D6HfVgiA.cjs';
5
5
  export { getBatchDepth, isComputed, isEffect, isEffectScope, isSignal, trigger } from 'alien-signals';
6
6
 
7
7
  declare function createEffect(fn: () => void | (() => void)): () => void;
@@ -125,21 +125,6 @@ declare function batch(fn: () => void): void;
125
125
  */
126
126
  declare function untrack<T>(fn: () => T): T;
127
127
 
128
- /**
129
- * Forma Reactive - Root
130
- *
131
- * Explicit reactive ownership scope. All effects created inside a root
132
- * are automatically disposed when the root is torn down.
133
- *
134
- * Uses alien-signals' `effectScope` under the hood for native graph-level
135
- * effect tracking, with a userland disposer list for non-effect cleanup
136
- * (e.g., event listeners, DOM references, timers).
137
- *
138
- * Roots created inside another root are automatically owned by the parent
139
- * (Solid-style). When the parent is disposed, all child roots are disposed
140
- * too. Use {@link createUnownedRoot} for roots that must outlive their
141
- * lexical parent (e.g., mount points, test harnesses).
142
- */
143
128
  /**
144
129
  * Create a reactive root scope.
145
130
  *
@@ -312,22 +297,23 @@ type Dispatch<A> = (action: A) => void;
312
297
  */
313
298
  declare function createReducer<S, A>(reducer: (state: S, action: A) => S, initialState: S): [state: SignalGetter<S>, dispatch: Dispatch<A>];
314
299
 
315
- /** Callback signature for the global {@link onError} handler. */
300
+ /** Callback signature for a global {@link onError} handler. */
316
301
  type ErrorHandler = (error: unknown, info?: {
317
302
  source?: string;
318
303
  }) => void;
319
304
  /**
320
- * Install a global error handler for FormaJS reactive errors.
321
- * Called when effects, computeds, or event handlers throw.
305
+ * Install a global error handler for FormaJS reactive errors. Called when
306
+ * effects, computeds, or event handlers throw. Multiple handlers may be
307
+ * registered; returns an unsubscribe function that removes only this handler.
322
308
  *
323
309
  * ```ts
324
- * onError((err, info) => {
325
- * console.error(`[${info?.source}]`, err);
326
- * Sentry.captureException(err);
310
+ * const off = onError((err, info) => {
311
+ * Sentry.captureException(err, { tags: { source: info?.source } });
327
312
  * });
313
+ * // later: off();
328
314
  * ```
329
315
  */
330
- declare function onError(handler: ErrorHandler): void;
316
+ declare function onError(handler: ErrorHandler): () => void;
331
317
 
332
318
  /**
333
319
  * Forma DOM - Element
@@ -957,6 +943,8 @@ interface HistoryControls<T> {
957
943
  cursor: () => number;
958
944
  /** Clear all history, keeping only the current value. */
959
945
  clear: () => void;
946
+ /** Stop tracking the source signal and release the history stack. */
947
+ destroy: () => void;
960
948
  }
961
949
  /**
962
950
  * Create undo/redo history tracking for a signal.
@@ -971,6 +959,13 @@ interface HistoryControls<T> {
971
959
  * h.redo(); // count() === 2
972
960
  * h.canUndo(); // true (reactive)
973
961
  * ```
962
+ *
963
+ * **Limitation:** the source must be a signal whose getter returns a stable
964
+ * value (a primitive or a stable object reference). A `createStore` slice whose
965
+ * getter returns a *fresh proxy on every read* is not supported: the undo/redo
966
+ * echo guard compares by identity, so a new proxy each read makes every
967
+ * undo/redo look like an external change and clears the redo history. Track
968
+ * store state with `setState`/direct mutation, not `createHistory`.
974
969
  */
975
970
  declare function createHistory<T>(source: [get: () => T, set: (v: T) => void], options?: {
976
971
  maxLength?: number;
@@ -983,6 +978,8 @@ declare function createHistory<T>(source: [get: () => T, set: (v: T) => void], o
983
978
  * Reads stored value on creation; writes on every signal change.
984
979
  * Zero dependencies -- native browser APIs only.
985
980
  */
981
+ /** The phase in which a persist operation failed, passed to {@link PersistOptions.onError}. */
982
+ type PersistErrorPhase = 'hydrate' | 'serialize' | 'write' | 'migrate';
986
983
  /** Options for {@link persist} — storage backend, serialization, and validation. */
987
984
  interface PersistOptions<T> {
988
985
  /** Storage backend. Defaults to localStorage. */
@@ -993,6 +990,14 @@ interface PersistOptions<T> {
993
990
  deserialize?: (s: string) => T;
994
991
  /** Optional validator — return true if the deserialized value is valid. Rejects corrupt/tampered data. */
995
992
  validate?: (v: unknown) => v is T;
993
+ /** Current schema version. When set, values are stored in a versioned envelope. */
994
+ version?: number;
995
+ /** Migrate stored data whose version is older than {@link version}. Runs before validate. */
996
+ migrate?: (oldValue: unknown, oldVersion: number) => T;
997
+ /** Re-hydrate when another tab writes this key. Defaults to true for localStorage. */
998
+ syncTabs?: boolean;
999
+ /** Report hydrate/serialize/write/migrate failures instead of swallowing them. */
1000
+ onError?: (err: unknown, phase: PersistErrorPhase) => void;
996
1001
  }
997
1002
  /**
998
1003
  * Persist a signal's value to storage.
@@ -1007,7 +1012,7 @@ interface PersistOptions<T> {
1007
1012
  * setTheme('dark'); // auto-saved to localStorage under key 'app:theme'
1008
1013
  * ```
1009
1014
  */
1010
- declare function persist<T>(source: [get: () => T, set: (v: T) => void], key: string, options?: PersistOptions<T>): void;
1015
+ declare function persist<T>(source: [get: () => T, set: (v: T) => void], key: string, options?: PersistOptions<T>): () => void;
1011
1016
 
1012
1017
  /**
1013
1018
  * A typed publish/subscribe event bus.
@@ -1170,4 +1175,4 @@ declare function onIntersect(el: HTMLElement, handler: (entry: IntersectionObser
1170
1175
  */
1171
1176
  declare function onMutation(el: HTMLElement, handler: (mutations: MutationRecord[]) => void, options?: MutationObserverInit): () => void;
1172
1177
 
1173
- export { $, $$, type CleanupFn, type ComponentDef, type Context, type CreateListOptions, type Dispatch, type ErrorHandler, type EventBus, Fragment, type HistoryControls, type IslandHydrateFn, type KeyOptions, type ListTransitionHooks, type PersistOptions, type ReconcileResult, type Ref, type SetupFn, SignalGetter, type StoreSetter, type SwitchCase, activateIslands, addClass, batch, children, cleanup, closest, createBus, createComputed, createContext, createEffect, createErrorBoundary, createHistory, createList, createMemo, createPortal, createReducer, createRef, createRoot, createShow, createStore, createSuspense, createSwitch, createText, createUnownedRoot, deactivateAllIslands, deactivateIsland, defineComponent, delegate, disposeComponent, fragment, h, hydrateIsland, inject, mount, nextSibling, on, onCleanup, onError, onIntersect, onKey, onMount, onMutation, onResize, onUnmount, parent, persist, prevSibling, provide, reconcileList, removeClass, setAttr, setHTMLUnsafe, setStyle, setText, siblings, template, templateMany, toggleClass, trackDisposer, unprovide, untrack };
1178
+ export { $, $$, type CleanupFn, type ComponentDef, type Context, type CreateListOptions, type Dispatch, type ErrorHandler, type EventBus, Fragment, type HistoryControls, type IslandHydrateFn, type KeyOptions, type ListTransitionHooks, type PersistErrorPhase, type PersistOptions, type ReconcileResult, type Ref, type SetupFn, SignalGetter, type StoreSetter, type SwitchCase, activateIslands, addClass, batch, children, cleanup, closest, createBus, createComputed, createContext, createEffect, createErrorBoundary, createHistory, createList, createMemo, createPortal, createReducer, createRef, createRoot, createShow, createStore, createSuspense, createSwitch, createText, createUnownedRoot, deactivateAllIslands, deactivateIsland, defineComponent, delegate, disposeComponent, fragment, h, hydrateIsland, inject, mount, nextSibling, on, onCleanup, onError, onIntersect, onKey, onMount, onMutation, onResize, onUnmount, parent, persist, prevSibling, provide, reconcileList, removeClass, setAttr, setHTMLUnsafe, setStyle, setText, siblings, template, templateMany, toggleClass, trackDisposer, unprovide, untrack };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /// <reference path="./jsx.d.ts" />
2
- import { S as SignalGetter } from './signal-C9v4akyJ.js';
3
- export { a as SignalOptions, b as SignalSetter, c as createSignal } from './signal-C9v4akyJ.js';
4
- export { R as Resource, a as ResourceOptions, c as createResource } from './resource-BHsgURy0.js';
2
+ import { S as SignalGetter } from './signal-CRBJYQ6B.js';
3
+ export { a as SignalOptions, b as SignalSetter, c as createSignal } from './signal-CRBJYQ6B.js';
4
+ export { R as Resource, a as ResourceOptions, c as createResource } from './resource-ljs2X5NM.js';
5
5
  export { getBatchDepth, isComputed, isEffect, isEffectScope, isSignal, trigger } from 'alien-signals';
6
6
 
7
7
  declare function createEffect(fn: () => void | (() => void)): () => void;
@@ -125,21 +125,6 @@ declare function batch(fn: () => void): void;
125
125
  */
126
126
  declare function untrack<T>(fn: () => T): T;
127
127
 
128
- /**
129
- * Forma Reactive - Root
130
- *
131
- * Explicit reactive ownership scope. All effects created inside a root
132
- * are automatically disposed when the root is torn down.
133
- *
134
- * Uses alien-signals' `effectScope` under the hood for native graph-level
135
- * effect tracking, with a userland disposer list for non-effect cleanup
136
- * (e.g., event listeners, DOM references, timers).
137
- *
138
- * Roots created inside another root are automatically owned by the parent
139
- * (Solid-style). When the parent is disposed, all child roots are disposed
140
- * too. Use {@link createUnownedRoot} for roots that must outlive their
141
- * lexical parent (e.g., mount points, test harnesses).
142
- */
143
128
  /**
144
129
  * Create a reactive root scope.
145
130
  *
@@ -312,22 +297,23 @@ type Dispatch<A> = (action: A) => void;
312
297
  */
313
298
  declare function createReducer<S, A>(reducer: (state: S, action: A) => S, initialState: S): [state: SignalGetter<S>, dispatch: Dispatch<A>];
314
299
 
315
- /** Callback signature for the global {@link onError} handler. */
300
+ /** Callback signature for a global {@link onError} handler. */
316
301
  type ErrorHandler = (error: unknown, info?: {
317
302
  source?: string;
318
303
  }) => void;
319
304
  /**
320
- * Install a global error handler for FormaJS reactive errors.
321
- * Called when effects, computeds, or event handlers throw.
305
+ * Install a global error handler for FormaJS reactive errors. Called when
306
+ * effects, computeds, or event handlers throw. Multiple handlers may be
307
+ * registered; returns an unsubscribe function that removes only this handler.
322
308
  *
323
309
  * ```ts
324
- * onError((err, info) => {
325
- * console.error(`[${info?.source}]`, err);
326
- * Sentry.captureException(err);
310
+ * const off = onError((err, info) => {
311
+ * Sentry.captureException(err, { tags: { source: info?.source } });
327
312
  * });
313
+ * // later: off();
328
314
  * ```
329
315
  */
330
- declare function onError(handler: ErrorHandler): void;
316
+ declare function onError(handler: ErrorHandler): () => void;
331
317
 
332
318
  /**
333
319
  * Forma DOM - Element
@@ -957,6 +943,8 @@ interface HistoryControls<T> {
957
943
  cursor: () => number;
958
944
  /** Clear all history, keeping only the current value. */
959
945
  clear: () => void;
946
+ /** Stop tracking the source signal and release the history stack. */
947
+ destroy: () => void;
960
948
  }
961
949
  /**
962
950
  * Create undo/redo history tracking for a signal.
@@ -971,6 +959,13 @@ interface HistoryControls<T> {
971
959
  * h.redo(); // count() === 2
972
960
  * h.canUndo(); // true (reactive)
973
961
  * ```
962
+ *
963
+ * **Limitation:** the source must be a signal whose getter returns a stable
964
+ * value (a primitive or a stable object reference). A `createStore` slice whose
965
+ * getter returns a *fresh proxy on every read* is not supported: the undo/redo
966
+ * echo guard compares by identity, so a new proxy each read makes every
967
+ * undo/redo look like an external change and clears the redo history. Track
968
+ * store state with `setState`/direct mutation, not `createHistory`.
974
969
  */
975
970
  declare function createHistory<T>(source: [get: () => T, set: (v: T) => void], options?: {
976
971
  maxLength?: number;
@@ -983,6 +978,8 @@ declare function createHistory<T>(source: [get: () => T, set: (v: T) => void], o
983
978
  * Reads stored value on creation; writes on every signal change.
984
979
  * Zero dependencies -- native browser APIs only.
985
980
  */
981
+ /** The phase in which a persist operation failed, passed to {@link PersistOptions.onError}. */
982
+ type PersistErrorPhase = 'hydrate' | 'serialize' | 'write' | 'migrate';
986
983
  /** Options for {@link persist} — storage backend, serialization, and validation. */
987
984
  interface PersistOptions<T> {
988
985
  /** Storage backend. Defaults to localStorage. */
@@ -993,6 +990,14 @@ interface PersistOptions<T> {
993
990
  deserialize?: (s: string) => T;
994
991
  /** Optional validator — return true if the deserialized value is valid. Rejects corrupt/tampered data. */
995
992
  validate?: (v: unknown) => v is T;
993
+ /** Current schema version. When set, values are stored in a versioned envelope. */
994
+ version?: number;
995
+ /** Migrate stored data whose version is older than {@link version}. Runs before validate. */
996
+ migrate?: (oldValue: unknown, oldVersion: number) => T;
997
+ /** Re-hydrate when another tab writes this key. Defaults to true for localStorage. */
998
+ syncTabs?: boolean;
999
+ /** Report hydrate/serialize/write/migrate failures instead of swallowing them. */
1000
+ onError?: (err: unknown, phase: PersistErrorPhase) => void;
996
1001
  }
997
1002
  /**
998
1003
  * Persist a signal's value to storage.
@@ -1007,7 +1012,7 @@ interface PersistOptions<T> {
1007
1012
  * setTheme('dark'); // auto-saved to localStorage under key 'app:theme'
1008
1013
  * ```
1009
1014
  */
1010
- declare function persist<T>(source: [get: () => T, set: (v: T) => void], key: string, options?: PersistOptions<T>): void;
1015
+ declare function persist<T>(source: [get: () => T, set: (v: T) => void], key: string, options?: PersistOptions<T>): () => void;
1011
1016
 
1012
1017
  /**
1013
1018
  * A typed publish/subscribe event bus.
@@ -1170,4 +1175,4 @@ declare function onIntersect(el: HTMLElement, handler: (entry: IntersectionObser
1170
1175
  */
1171
1176
  declare function onMutation(el: HTMLElement, handler: (mutations: MutationRecord[]) => void, options?: MutationObserverInit): () => void;
1172
1177
 
1173
- export { $, $$, type CleanupFn, type ComponentDef, type Context, type CreateListOptions, type Dispatch, type ErrorHandler, type EventBus, Fragment, type HistoryControls, type IslandHydrateFn, type KeyOptions, type ListTransitionHooks, type PersistOptions, type ReconcileResult, type Ref, type SetupFn, SignalGetter, type StoreSetter, type SwitchCase, activateIslands, addClass, batch, children, cleanup, closest, createBus, createComputed, createContext, createEffect, createErrorBoundary, createHistory, createList, createMemo, createPortal, createReducer, createRef, createRoot, createShow, createStore, createSuspense, createSwitch, createText, createUnownedRoot, deactivateAllIslands, deactivateIsland, defineComponent, delegate, disposeComponent, fragment, h, hydrateIsland, inject, mount, nextSibling, on, onCleanup, onError, onIntersect, onKey, onMount, onMutation, onResize, onUnmount, parent, persist, prevSibling, provide, reconcileList, removeClass, setAttr, setHTMLUnsafe, setStyle, setText, siblings, template, templateMany, toggleClass, trackDisposer, unprovide, untrack };
1178
+ export { $, $$, type CleanupFn, type ComponentDef, type Context, type CreateListOptions, type Dispatch, type ErrorHandler, type EventBus, Fragment, type HistoryControls, type IslandHydrateFn, type KeyOptions, type ListTransitionHooks, type PersistErrorPhase, type PersistOptions, type ReconcileResult, type Ref, type SetupFn, SignalGetter, type StoreSetter, type SwitchCase, activateIslands, addClass, batch, children, cleanup, closest, createBus, createComputed, createContext, createEffect, createErrorBoundary, createHistory, createList, createMemo, createPortal, createReducer, createRef, createRoot, createShow, createStore, createSuspense, createSwitch, createText, createUnownedRoot, deactivateAllIslands, deactivateIsland, defineComponent, delegate, disposeComponent, fragment, h, hydrateIsland, inject, mount, nextSibling, on, onCleanup, onError, onIntersect, onKey, onMount, onMutation, onResize, onUnmount, parent, persist, prevSibling, provide, reconcileList, removeClass, setAttr, setHTMLUnsafe, setStyle, setText, siblings, template, templateMany, toggleClass, trackDisposer, unprovide, untrack };