@getforma/core 0.3.0 → 0.3.1

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 (38) hide show
  1. package/README.md +19 -5
  2. package/dist/{chunk-VKKPX4YU.js → chunk-5H52PKGF.js} +62 -12
  3. package/dist/chunk-5H52PKGF.js.map +1 -0
  4. package/dist/{chunk-VP5EOGM5.cjs → chunk-TSQ7AKFT.cjs} +62 -11
  5. package/dist/chunk-TSQ7AKFT.cjs.map +1 -0
  6. package/dist/forma-runtime-csp.js +2 -0
  7. package/dist/forma-runtime.js +2 -0
  8. package/dist/formajs-runtime-hardened.global.js +1 -1
  9. package/dist/formajs-runtime-hardened.global.js.map +1 -1
  10. package/dist/formajs-runtime.global.js +1 -1
  11. package/dist/formajs-runtime.global.js.map +1 -1
  12. package/dist/formajs.global.js +1 -1
  13. package/dist/formajs.global.js.map +1 -1
  14. package/dist/index.cjs +100 -69
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +43 -27
  17. package/dist/index.d.ts +43 -27
  18. package/dist/index.js +57 -27
  19. package/dist/index.js.map +1 -1
  20. package/dist/runtime-hardened.cjs +166 -50
  21. package/dist/runtime-hardened.cjs.map +1 -1
  22. package/dist/runtime-hardened.d.cts +86 -0
  23. package/dist/runtime-hardened.d.ts +86 -0
  24. package/dist/runtime-hardened.js +166 -50
  25. package/dist/runtime-hardened.js.map +1 -1
  26. package/dist/runtime.cjs +188 -72
  27. package/dist/runtime.cjs.map +1 -1
  28. package/dist/runtime.js +167 -51
  29. package/dist/runtime.js.map +1 -1
  30. package/dist/ssr/index.cjs +59 -71
  31. package/dist/ssr/index.cjs.map +1 -1
  32. package/dist/ssr/index.d.cts +4 -0
  33. package/dist/ssr/index.d.ts +4 -0
  34. package/dist/ssr/index.js +59 -71
  35. package/dist/ssr/index.js.map +1 -1
  36. package/package.json +24 -3
  37. package/dist/chunk-VKKPX4YU.js.map +0 -1
  38. package/dist/chunk-VP5EOGM5.cjs.map +0 -1
package/dist/index.d.cts CHANGED
@@ -924,6 +924,8 @@ interface PersistOptions<T> {
924
924
  serialize?: (v: T) => string;
925
925
  /** Custom deserializer. Defaults to JSON.parse. */
926
926
  deserialize?: (s: string) => T;
927
+ /** Optional validator — return true if the deserialized value is valid. Rejects corrupt/tampered data. */
928
+ validate?: (v: unknown) => v is T;
927
929
  }
928
930
  /**
929
931
  * Persist a signal's value to storage.
@@ -940,14 +942,14 @@ interface PersistOptions<T> {
940
942
  */
941
943
  declare function persist<T>(source: [get: () => T, set: (v: T) => void], key: string, options?: PersistOptions<T>): void;
942
944
 
943
- interface EventBus<T extends Record<string, any>> {
945
+ interface EventBus<T extends Record<string, unknown>> {
944
946
  on<K extends keyof T>(event: K, handler: (payload: T[K]) => void): () => void;
945
947
  once<K extends keyof T>(event: K, handler: (payload: T[K]) => void): () => void;
946
948
  emit<K extends keyof T>(event: K, payload: T[K]): void;
947
949
  off<K extends keyof T>(event: K, handler: (payload: T[K]) => void): void;
948
950
  clear(): void;
949
951
  }
950
- declare function createBus<T extends Record<string, any> = Record<string, any>>(): EventBus<T>;
952
+ declare function createBus<T extends Record<string, unknown> = Record<string, unknown>>(): EventBus<T>;
951
953
 
952
954
  declare function delegate<K extends keyof HTMLElementEventMap>(container: HTMLElement | Document, selector: string, event: K, handler: (e: HTMLElementEventMap[K], matchedEl: HTMLElement) => void, options?: AddEventListenerOptions): () => void;
953
955
 
@@ -967,7 +969,22 @@ declare function toggleClass(el: HTMLElement, className: string, force?: boolean
967
969
  declare function setStyle(el: HTMLElement, styles: Partial<CSSStyleDeclaration>): void;
968
970
  declare function setAttr(el: HTMLElement, attrs: Record<string, string | boolean | null>): void;
969
971
  declare function setText(el: HTMLElement, text: string): void;
972
+ /**
973
+ * Set raw HTML on an element. **No sanitization is performed.**
974
+ *
975
+ * Prefer `setText()` for user-controlled content. Only use this when you
976
+ * trust the HTML source (e.g., server-rendered markup you control).
977
+ *
978
+ * @deprecated Use `setHTMLUnsafe` instead — renamed to signal risk.
979
+ */
970
980
  declare function setHTML(el: HTMLElement, html: string): void;
981
+ /**
982
+ * Set raw HTML on an element. **No sanitization is performed.**
983
+ *
984
+ * Prefer `setText()` for user-controlled content. Only use this when you
985
+ * trust the HTML source (e.g., server-rendered markup you control).
986
+ */
987
+ declare function setHTMLUnsafe(el: HTMLElement, html: string): void;
971
988
 
972
989
  declare function closest<T extends HTMLElement = HTMLElement>(el: HTMLElement, selector: string): T | null;
973
990
  declare function children<T extends HTMLElement = HTMLElement>(el: HTMLElement, selector?: string): T[];
@@ -980,22 +997,26 @@ declare function onResize(el: HTMLElement, handler: (entry: ResizeObserverEntry)
980
997
  declare function onIntersect(el: HTMLElement, handler: (entry: IntersectionObserverEntry) => void, options?: IntersectionObserverInit): () => void;
981
998
  declare function onMutation(el: HTMLElement, handler: (mutations: MutationRecord[]) => void, options?: MutationObserverInit): () => void;
982
999
 
983
- /**
984
- * Forma Storage - Local
985
- *
986
- * Typed localStorage wrapper with graceful error handling.
987
- * Zero dependencies — native browser APIs only.
988
- */
989
- interface TypedStorage$1<T> {
1000
+ interface TypedStorage<T> {
990
1001
  get(): T | null;
991
1002
  set(value: T): void;
992
1003
  remove(): void;
993
1004
  key: string;
994
1005
  }
995
- interface StorageOptions$1<T> {
1006
+ interface StorageOptions<T> {
996
1007
  serialize?: (v: T) => string;
997
1008
  deserialize?: (s: string) => T;
1009
+ /** Optional validator — return true if the deserialized value is valid. */
1010
+ validate?: (v: unknown) => v is T;
998
1011
  }
1012
+
1013
+ /**
1014
+ * Forma Storage - Local
1015
+ *
1016
+ * Typed localStorage wrapper with graceful error handling.
1017
+ * Zero dependencies — native browser APIs only.
1018
+ */
1019
+
999
1020
  /**
1000
1021
  * Create a typed localStorage wrapper for the given key.
1001
1022
  *
@@ -1006,7 +1027,7 @@ interface StorageOptions$1<T> {
1006
1027
  * store.remove();
1007
1028
  * ```
1008
1029
  */
1009
- declare function createLocalStorage<T>(key: string, options?: StorageOptions$1<T>): TypedStorage$1<T>;
1030
+ declare function createLocalStorage<T>(key: string, options?: StorageOptions<T>): TypedStorage<T>;
1010
1031
 
1011
1032
  /**
1012
1033
  * Forma Storage - Session
@@ -1014,16 +1035,7 @@ declare function createLocalStorage<T>(key: string, options?: StorageOptions$1<T
1014
1035
  * Typed sessionStorage wrapper with graceful error handling.
1015
1036
  * Zero dependencies — native browser APIs only.
1016
1037
  */
1017
- interface TypedStorage<T> {
1018
- get(): T | null;
1019
- set(value: T): void;
1020
- remove(): void;
1021
- key: string;
1022
- }
1023
- interface StorageOptions<T> {
1024
- serialize?: (v: T) => string;
1025
- deserialize?: (s: string) => T;
1026
- }
1038
+
1027
1039
  /**
1028
1040
  * Create a typed sessionStorage wrapper for the given key.
1029
1041
  *
@@ -1106,9 +1118,11 @@ declare function fetchJSON<T>(url: string, options?: RequestInit): Promise<T>;
1106
1118
  * Reactive SSE wrapper with signal integration.
1107
1119
  * Zero dependencies — native browser APIs only.
1108
1120
  */
1109
- interface SSEOptions {
1121
+ interface SSEOptions<T = unknown> {
1110
1122
  withCredentials?: boolean;
1111
1123
  headers?: Record<string, string>;
1124
+ /** Custom parser for incoming messages. Defaults to JSON.parse with raw data fallback. */
1125
+ parse?: (data: string) => T;
1112
1126
  }
1113
1127
  interface SSEConnection<T = unknown> {
1114
1128
  data: () => T | null;
@@ -1128,7 +1142,7 @@ interface SSEConnection<T = unknown> {
1128
1142
  * });
1129
1143
  * ```
1130
1144
  */
1131
- declare function createSSE<T = unknown>(url: string, options?: SSEOptions): SSEConnection<T>;
1145
+ declare function createSSE<T = unknown>(url: string, options?: SSEOptions<T>): SSEConnection<T>;
1132
1146
 
1133
1147
  /**
1134
1148
  * Forma HTTP - WebSocket
@@ -1137,11 +1151,13 @@ declare function createSSE<T = unknown>(url: string, options?: SSEOptions): SSEC
1137
1151
  * Zero dependencies — native browser APIs only.
1138
1152
  */
1139
1153
  type WSStatus = 'connecting' | 'open' | 'closed' | 'error';
1140
- interface WSOptions {
1154
+ interface WSOptions<TReceive = unknown> {
1141
1155
  protocols?: string | string[];
1142
1156
  reconnect?: boolean;
1143
1157
  reconnectInterval?: number;
1144
1158
  maxReconnects?: number;
1159
+ /** Custom parser for incoming messages. Defaults to JSON.parse with raw data fallback. */
1160
+ parse?: (data: string) => TReceive;
1145
1161
  }
1146
1162
  interface WSConnection<TSend = unknown, TReceive = unknown> {
1147
1163
  data: () => TReceive | null;
@@ -1162,7 +1178,7 @@ interface WSConnection<TSend = unknown, TReceive = unknown> {
1162
1178
  * });
1163
1179
  * ```
1164
1180
  */
1165
- declare function createWebSocket<TSend = unknown, TReceive = unknown>(url: string, options?: WSOptions): WSConnection<TSend, TReceive>;
1181
+ declare function createWebSocket<TSend = unknown, TReceive = unknown>(url: string, options?: WSOptions<TReceive>): WSConnection<TSend, TReceive>;
1166
1182
 
1167
1183
  /**
1168
1184
  * FormaJS Server - Action
@@ -1327,7 +1343,7 @@ declare function withRevalidation<T>(data: T, revalidate: Record<string, unknown
1327
1343
  * @param endpoint - The RPC endpoint path (e.g. "/rpc/createTodo_a1b2c3")
1328
1344
  * @returns An async function that sends args to the server and returns the result
1329
1345
  */
1330
- declare function $$serverFunction<T extends (...args: any[]) => Promise<any>>(endpoint: string): T;
1346
+ declare function $$serverFunction<T extends (...args: unknown[]) => Promise<unknown>>(endpoint: string): T;
1331
1347
 
1332
1348
  /**
1333
1349
  * FormaJS Server - RPC Handler
@@ -1391,4 +1407,4 @@ declare function renderLocal(slotsJson: string): Promise<string>;
1391
1407
  /** Fragment render (single island) via WASM. */
1392
1408
  declare function renderIsland(slotsJson: string, islandId: number): Promise<string>;
1393
1409
 
1394
- export { $, $$, $$serverFunction, type Action, type ActionOptions, Fragment, type IslandHydrateFn, type MutationResponse, type RPCRequest, type RPCResponse, activateIslands, addClass, applyRevalidation, batch, children, cleanup, closest, createAction, createBus, createComputed, createContext, createEffect, createErrorBoundary, createFetch, createHistory, createIndexedDB, createList, createLocalStorage, createMemo, createPortal, createRPCMiddleware, createReducer, createRef, createResource, createRoot, createSSE, createSessionStorage, createShow, createStore, createSuspense, createSwitch, createText, createWebSocket, defineComponent, delegate, disposeComponent, enableAutoRevalidation, fetchJSON, fragment, getRegisteredEndpoints, getServerFunction, h, handleRPC, hydrateIsland, inject, longestIncreasingSubsequence, mount, nextSibling, on, onCleanup, onError, onIntersect, onKey, onMount, onMutation, onResize, onUnmount, parent, persist, prevSibling, provide, reconcileList, registerResource, registerServerFunction, removeClass, renderIsland, renderLocal, setAttr, setHTML, setStyle, setText, siblings, toggleClass, trackDisposer, unprovide, unregisterResource, untrack, withRevalidation };
1410
+ export { $, $$, $$serverFunction, type Action, type ActionOptions, Fragment, type IslandHydrateFn, type MutationResponse, type RPCRequest, type RPCResponse, activateIslands, addClass, applyRevalidation, batch, children, cleanup, closest, createAction, createBus, createComputed, createContext, createEffect, createErrorBoundary, createFetch, createHistory, createIndexedDB, createList, createLocalStorage, createMemo, createPortal, createRPCMiddleware, createReducer, createRef, createResource, createRoot, createSSE, createSessionStorage, createShow, createStore, createSuspense, createSwitch, createText, createWebSocket, defineComponent, delegate, disposeComponent, enableAutoRevalidation, fetchJSON, fragment, getRegisteredEndpoints, getServerFunction, h, handleRPC, hydrateIsland, inject, longestIncreasingSubsequence, mount, nextSibling, on, onCleanup, onError, onIntersect, onKey, onMount, onMutation, onResize, onUnmount, parent, persist, prevSibling, provide, reconcileList, registerResource, registerServerFunction, removeClass, renderIsland, renderLocal, setAttr, setHTML, setHTMLUnsafe, setStyle, setText, siblings, toggleClass, trackDisposer, unprovide, unregisterResource, untrack, withRevalidation };
package/dist/index.d.ts CHANGED
@@ -924,6 +924,8 @@ interface PersistOptions<T> {
924
924
  serialize?: (v: T) => string;
925
925
  /** Custom deserializer. Defaults to JSON.parse. */
926
926
  deserialize?: (s: string) => T;
927
+ /** Optional validator — return true if the deserialized value is valid. Rejects corrupt/tampered data. */
928
+ validate?: (v: unknown) => v is T;
927
929
  }
928
930
  /**
929
931
  * Persist a signal's value to storage.
@@ -940,14 +942,14 @@ interface PersistOptions<T> {
940
942
  */
941
943
  declare function persist<T>(source: [get: () => T, set: (v: T) => void], key: string, options?: PersistOptions<T>): void;
942
944
 
943
- interface EventBus<T extends Record<string, any>> {
945
+ interface EventBus<T extends Record<string, unknown>> {
944
946
  on<K extends keyof T>(event: K, handler: (payload: T[K]) => void): () => void;
945
947
  once<K extends keyof T>(event: K, handler: (payload: T[K]) => void): () => void;
946
948
  emit<K extends keyof T>(event: K, payload: T[K]): void;
947
949
  off<K extends keyof T>(event: K, handler: (payload: T[K]) => void): void;
948
950
  clear(): void;
949
951
  }
950
- declare function createBus<T extends Record<string, any> = Record<string, any>>(): EventBus<T>;
952
+ declare function createBus<T extends Record<string, unknown> = Record<string, unknown>>(): EventBus<T>;
951
953
 
952
954
  declare function delegate<K extends keyof HTMLElementEventMap>(container: HTMLElement | Document, selector: string, event: K, handler: (e: HTMLElementEventMap[K], matchedEl: HTMLElement) => void, options?: AddEventListenerOptions): () => void;
953
955
 
@@ -967,7 +969,22 @@ declare function toggleClass(el: HTMLElement, className: string, force?: boolean
967
969
  declare function setStyle(el: HTMLElement, styles: Partial<CSSStyleDeclaration>): void;
968
970
  declare function setAttr(el: HTMLElement, attrs: Record<string, string | boolean | null>): void;
969
971
  declare function setText(el: HTMLElement, text: string): void;
972
+ /**
973
+ * Set raw HTML on an element. **No sanitization is performed.**
974
+ *
975
+ * Prefer `setText()` for user-controlled content. Only use this when you
976
+ * trust the HTML source (e.g., server-rendered markup you control).
977
+ *
978
+ * @deprecated Use `setHTMLUnsafe` instead — renamed to signal risk.
979
+ */
970
980
  declare function setHTML(el: HTMLElement, html: string): void;
981
+ /**
982
+ * Set raw HTML on an element. **No sanitization is performed.**
983
+ *
984
+ * Prefer `setText()` for user-controlled content. Only use this when you
985
+ * trust the HTML source (e.g., server-rendered markup you control).
986
+ */
987
+ declare function setHTMLUnsafe(el: HTMLElement, html: string): void;
971
988
 
972
989
  declare function closest<T extends HTMLElement = HTMLElement>(el: HTMLElement, selector: string): T | null;
973
990
  declare function children<T extends HTMLElement = HTMLElement>(el: HTMLElement, selector?: string): T[];
@@ -980,22 +997,26 @@ declare function onResize(el: HTMLElement, handler: (entry: ResizeObserverEntry)
980
997
  declare function onIntersect(el: HTMLElement, handler: (entry: IntersectionObserverEntry) => void, options?: IntersectionObserverInit): () => void;
981
998
  declare function onMutation(el: HTMLElement, handler: (mutations: MutationRecord[]) => void, options?: MutationObserverInit): () => void;
982
999
 
983
- /**
984
- * Forma Storage - Local
985
- *
986
- * Typed localStorage wrapper with graceful error handling.
987
- * Zero dependencies — native browser APIs only.
988
- */
989
- interface TypedStorage$1<T> {
1000
+ interface TypedStorage<T> {
990
1001
  get(): T | null;
991
1002
  set(value: T): void;
992
1003
  remove(): void;
993
1004
  key: string;
994
1005
  }
995
- interface StorageOptions$1<T> {
1006
+ interface StorageOptions<T> {
996
1007
  serialize?: (v: T) => string;
997
1008
  deserialize?: (s: string) => T;
1009
+ /** Optional validator — return true if the deserialized value is valid. */
1010
+ validate?: (v: unknown) => v is T;
998
1011
  }
1012
+
1013
+ /**
1014
+ * Forma Storage - Local
1015
+ *
1016
+ * Typed localStorage wrapper with graceful error handling.
1017
+ * Zero dependencies — native browser APIs only.
1018
+ */
1019
+
999
1020
  /**
1000
1021
  * Create a typed localStorage wrapper for the given key.
1001
1022
  *
@@ -1006,7 +1027,7 @@ interface StorageOptions$1<T> {
1006
1027
  * store.remove();
1007
1028
  * ```
1008
1029
  */
1009
- declare function createLocalStorage<T>(key: string, options?: StorageOptions$1<T>): TypedStorage$1<T>;
1030
+ declare function createLocalStorage<T>(key: string, options?: StorageOptions<T>): TypedStorage<T>;
1010
1031
 
1011
1032
  /**
1012
1033
  * Forma Storage - Session
@@ -1014,16 +1035,7 @@ declare function createLocalStorage<T>(key: string, options?: StorageOptions$1<T
1014
1035
  * Typed sessionStorage wrapper with graceful error handling.
1015
1036
  * Zero dependencies — native browser APIs only.
1016
1037
  */
1017
- interface TypedStorage<T> {
1018
- get(): T | null;
1019
- set(value: T): void;
1020
- remove(): void;
1021
- key: string;
1022
- }
1023
- interface StorageOptions<T> {
1024
- serialize?: (v: T) => string;
1025
- deserialize?: (s: string) => T;
1026
- }
1038
+
1027
1039
  /**
1028
1040
  * Create a typed sessionStorage wrapper for the given key.
1029
1041
  *
@@ -1106,9 +1118,11 @@ declare function fetchJSON<T>(url: string, options?: RequestInit): Promise<T>;
1106
1118
  * Reactive SSE wrapper with signal integration.
1107
1119
  * Zero dependencies — native browser APIs only.
1108
1120
  */
1109
- interface SSEOptions {
1121
+ interface SSEOptions<T = unknown> {
1110
1122
  withCredentials?: boolean;
1111
1123
  headers?: Record<string, string>;
1124
+ /** Custom parser for incoming messages. Defaults to JSON.parse with raw data fallback. */
1125
+ parse?: (data: string) => T;
1112
1126
  }
1113
1127
  interface SSEConnection<T = unknown> {
1114
1128
  data: () => T | null;
@@ -1128,7 +1142,7 @@ interface SSEConnection<T = unknown> {
1128
1142
  * });
1129
1143
  * ```
1130
1144
  */
1131
- declare function createSSE<T = unknown>(url: string, options?: SSEOptions): SSEConnection<T>;
1145
+ declare function createSSE<T = unknown>(url: string, options?: SSEOptions<T>): SSEConnection<T>;
1132
1146
 
1133
1147
  /**
1134
1148
  * Forma HTTP - WebSocket
@@ -1137,11 +1151,13 @@ declare function createSSE<T = unknown>(url: string, options?: SSEOptions): SSEC
1137
1151
  * Zero dependencies — native browser APIs only.
1138
1152
  */
1139
1153
  type WSStatus = 'connecting' | 'open' | 'closed' | 'error';
1140
- interface WSOptions {
1154
+ interface WSOptions<TReceive = unknown> {
1141
1155
  protocols?: string | string[];
1142
1156
  reconnect?: boolean;
1143
1157
  reconnectInterval?: number;
1144
1158
  maxReconnects?: number;
1159
+ /** Custom parser for incoming messages. Defaults to JSON.parse with raw data fallback. */
1160
+ parse?: (data: string) => TReceive;
1145
1161
  }
1146
1162
  interface WSConnection<TSend = unknown, TReceive = unknown> {
1147
1163
  data: () => TReceive | null;
@@ -1162,7 +1178,7 @@ interface WSConnection<TSend = unknown, TReceive = unknown> {
1162
1178
  * });
1163
1179
  * ```
1164
1180
  */
1165
- declare function createWebSocket<TSend = unknown, TReceive = unknown>(url: string, options?: WSOptions): WSConnection<TSend, TReceive>;
1181
+ declare function createWebSocket<TSend = unknown, TReceive = unknown>(url: string, options?: WSOptions<TReceive>): WSConnection<TSend, TReceive>;
1166
1182
 
1167
1183
  /**
1168
1184
  * FormaJS Server - Action
@@ -1327,7 +1343,7 @@ declare function withRevalidation<T>(data: T, revalidate: Record<string, unknown
1327
1343
  * @param endpoint - The RPC endpoint path (e.g. "/rpc/createTodo_a1b2c3")
1328
1344
  * @returns An async function that sends args to the server and returns the result
1329
1345
  */
1330
- declare function $$serverFunction<T extends (...args: any[]) => Promise<any>>(endpoint: string): T;
1346
+ declare function $$serverFunction<T extends (...args: unknown[]) => Promise<unknown>>(endpoint: string): T;
1331
1347
 
1332
1348
  /**
1333
1349
  * FormaJS Server - RPC Handler
@@ -1391,4 +1407,4 @@ declare function renderLocal(slotsJson: string): Promise<string>;
1391
1407
  /** Fragment render (single island) via WASM. */
1392
1408
  declare function renderIsland(slotsJson: string, islandId: number): Promise<string>;
1393
1409
 
1394
- export { $, $$, $$serverFunction, type Action, type ActionOptions, Fragment, type IslandHydrateFn, type MutationResponse, type RPCRequest, type RPCResponse, activateIslands, addClass, applyRevalidation, batch, children, cleanup, closest, createAction, createBus, createComputed, createContext, createEffect, createErrorBoundary, createFetch, createHistory, createIndexedDB, createList, createLocalStorage, createMemo, createPortal, createRPCMiddleware, createReducer, createRef, createResource, createRoot, createSSE, createSessionStorage, createShow, createStore, createSuspense, createSwitch, createText, createWebSocket, defineComponent, delegate, disposeComponent, enableAutoRevalidation, fetchJSON, fragment, getRegisteredEndpoints, getServerFunction, h, handleRPC, hydrateIsland, inject, longestIncreasingSubsequence, mount, nextSibling, on, onCleanup, onError, onIntersect, onKey, onMount, onMutation, onResize, onUnmount, parent, persist, prevSibling, provide, reconcileList, registerResource, registerServerFunction, removeClass, renderIsland, renderLocal, setAttr, setHTML, setStyle, setText, siblings, toggleClass, trackDisposer, unprovide, unregisterResource, untrack, withRevalidation };
1410
+ export { $, $$, $$serverFunction, type Action, type ActionOptions, Fragment, type IslandHydrateFn, type MutationResponse, type RPCRequest, type RPCResponse, activateIslands, addClass, applyRevalidation, batch, children, cleanup, closest, createAction, createBus, createComputed, createContext, createEffect, createErrorBoundary, createFetch, createHistory, createIndexedDB, createList, createLocalStorage, createMemo, createPortal, createRPCMiddleware, createReducer, createRef, createResource, createRoot, createSSE, createSessionStorage, createShow, createStore, createSuspense, createSwitch, createText, createWebSocket, defineComponent, delegate, disposeComponent, enableAutoRevalidation, fetchJSON, fragment, getRegisteredEndpoints, getServerFunction, h, handleRPC, hydrateIsland, inject, longestIncreasingSubsequence, mount, nextSibling, on, onCleanup, onError, onIntersect, onKey, onMount, onMutation, onResize, onUnmount, parent, persist, prevSibling, provide, reconcileList, registerResource, registerServerFunction, removeClass, renderIsland, renderLocal, setAttr, setHTML, setHTMLUnsafe, setStyle, setText, siblings, toggleClass, trackDisposer, unprovide, unregisterResource, untrack, withRevalidation };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { internalEffect, createRoot, hydrateIsland, untrack, createEffect, pushSuspenseContext, popSuspenseContext, batch } from './chunk-VKKPX4YU.js';
2
- export { Fragment, batch, cleanup, createEffect, createList, createMemo, createReducer, createRef, createResource, createRoot, createShow, fragment, h, hydrateIsland, longestIncreasingSubsequence, on, onCleanup, onError, reconcileList, untrack } from './chunk-VKKPX4YU.js';
1
+ import { internalEffect, createRoot, hydrateIsland, untrack, createEffect, pushSuspenseContext, popSuspenseContext, __DEV__, batch } from './chunk-5H52PKGF.js';
2
+ export { Fragment, batch, cleanup, createEffect, createList, createMemo, createReducer, createRef, createResource, createRoot, createShow, fragment, h, hydrateIsland, longestIncreasingSubsequence, on, onCleanup, onError, reconcileList, untrack } from './chunk-5H52PKGF.js';
3
3
  import { createSignal, createValueSignal } from './chunk-KX5WRZH7.js';
4
4
  export { createComputed, createSignal } from './chunk-KX5WRZH7.js';
5
5
 
@@ -238,13 +238,13 @@ function activateIslands(registry2) {
238
238
  const componentName = root.getAttribute("data-forma-component");
239
239
  const hydrateFn = registry2[componentName];
240
240
  if (!hydrateFn) {
241
- console.warn(`[forma] No hydrate function for island "${componentName}" (id=${id})`);
241
+ if (__DEV__) console.warn(`[forma] No hydrate function for island "${componentName}" (id=${id})`);
242
242
  root.setAttribute("data-forma-status", "error");
243
243
  continue;
244
244
  }
245
245
  const trigger = root.getAttribute("data-forma-hydrate") || "load";
246
246
  if (trigger === "interaction" || trigger === "idle") {
247
- console.warn(`[forma] Trigger "${trigger}" not yet implemented for island "${componentName}" (id=${id}), falling back to load`);
247
+ if (__DEV__) console.warn(`[forma] Trigger "${trigger}" not yet implemented for island "${componentName}" (id=${id}), falling back to load`);
248
248
  }
249
249
  if (trigger === "visible") {
250
250
  const observer = new IntersectionObserver(
@@ -274,7 +274,7 @@ function hydrateIslandRoot(root, id, componentName, hydrateFn, sharedProps) {
274
274
  });
275
275
  activeRoot.setAttribute("data-forma-status", "active");
276
276
  } catch (err) {
277
- console.error(`[forma] Island "${componentName}" (id=${id}) failed:`, err);
277
+ if (__DEV__) console.error(`[forma] Island "${componentName}" (id=${id}) failed:`, err);
278
278
  root.setAttribute("data-forma-status", "error");
279
279
  }
280
280
  }
@@ -685,11 +685,14 @@ function persist(source, key, options) {
685
685
  const storage = options?.storage ?? globalThis.localStorage;
686
686
  const serialize = options?.serialize ?? JSON.stringify;
687
687
  const deserialize = options?.deserialize ?? JSON.parse;
688
+ const validate = options?.validate;
688
689
  try {
689
690
  const stored = storage.getItem(key);
690
691
  if (stored !== null) {
691
692
  const value = deserialize(stored);
692
- sourceSet(value);
693
+ if (!validate || validate(value)) {
694
+ sourceSet(value);
695
+ }
693
696
  }
694
697
  } catch {
695
698
  }
@@ -870,6 +873,9 @@ function setText(el, text) {
870
873
  function setHTML(el, html) {
871
874
  el.innerHTML = html;
872
875
  }
876
+ function setHTMLUnsafe(el, html) {
877
+ el.innerHTML = html;
878
+ }
873
879
 
874
880
  // src/dom-utils/traverse.ts
875
881
  function closest(el, selector) {
@@ -953,20 +959,26 @@ function onMutation(el, handler, options) {
953
959
  function createLocalStorage(key, options) {
954
960
  const serialize = options?.serialize ?? JSON.stringify;
955
961
  const deserialize = options?.deserialize ?? JSON.parse;
962
+ const validate = options?.validate;
956
963
  return {
957
964
  key,
958
965
  get() {
959
966
  try {
960
967
  const raw = localStorage.getItem(key);
961
968
  if (raw === null) return null;
962
- return deserialize(raw);
969
+ const value = deserialize(raw);
970
+ if (validate && !validate(value)) return null;
971
+ return value;
963
972
  } catch {
964
973
  return null;
965
974
  }
966
975
  },
967
976
  set(value) {
968
- const serialized = serialize(value);
969
- localStorage.setItem(key, serialized);
977
+ try {
978
+ const serialized = serialize(value);
979
+ localStorage.setItem(key, serialized);
980
+ } catch {
981
+ }
970
982
  },
971
983
  remove() {
972
984
  localStorage.removeItem(key);
@@ -978,20 +990,26 @@ function createLocalStorage(key, options) {
978
990
  function createSessionStorage(key, options) {
979
991
  const serialize = options?.serialize ?? JSON.stringify;
980
992
  const deserialize = options?.deserialize ?? JSON.parse;
993
+ const validate = options?.validate;
981
994
  return {
982
995
  key,
983
996
  get() {
984
997
  try {
985
998
  const raw = sessionStorage.getItem(key);
986
999
  if (raw === null) return null;
987
- return deserialize(raw);
1000
+ const value = deserialize(raw);
1001
+ if (validate && !validate(value)) return null;
1002
+ return value;
988
1003
  } catch {
989
1004
  return null;
990
1005
  }
991
1006
  },
992
1007
  set(value) {
993
- const serialized = serialize(value);
994
- sessionStorage.setItem(key, serialized);
1008
+ try {
1009
+ const serialized = serialize(value);
1010
+ sessionStorage.setItem(key, serialized);
1011
+ } catch {
1012
+ }
995
1013
  },
996
1014
  remove() {
997
1015
  sessionStorage.removeItem(key);
@@ -1122,7 +1140,7 @@ function createFetch(url, options) {
1122
1140
  const transformed = transform ? transform(json) : json;
1123
1141
  setData(transformed);
1124
1142
  } catch (err) {
1125
- if (err?.name === "AbortError") {
1143
+ if (err instanceof Error && err.name === "AbortError") {
1126
1144
  return;
1127
1145
  }
1128
1146
  setError(err instanceof Error ? err : new Error(String(err)));
@@ -1174,13 +1192,15 @@ function createSSE(url, options) {
1174
1192
  setConnected(true);
1175
1193
  setError(null);
1176
1194
  };
1177
- source.onmessage = (event) => {
1195
+ const parseMessage = options?.parse ?? ((raw) => {
1178
1196
  try {
1179
- const parsed = JSON.parse(event.data);
1180
- setData(parsed);
1197
+ return JSON.parse(raw);
1181
1198
  } catch {
1182
- setData(event.data);
1199
+ return raw;
1183
1200
  }
1201
+ });
1202
+ source.onmessage = (event) => {
1203
+ setData(parseMessage(event.data));
1184
1204
  };
1185
1205
  source.onerror = (event) => {
1186
1206
  setError(event);
@@ -1195,12 +1215,15 @@ function createSSE(url, options) {
1195
1215
  setConnected(false);
1196
1216
  },
1197
1217
  on(event, handler) {
1198
- const listener = (e) => {
1218
+ const parseEvent = options?.parse ?? ((raw) => {
1199
1219
  try {
1200
- handler(JSON.parse(e.data));
1220
+ return JSON.parse(raw);
1201
1221
  } catch {
1202
- handler(e.data);
1222
+ return raw;
1203
1223
  }
1224
+ });
1225
+ const listener = (e) => {
1226
+ handler(parseEvent(e.data));
1204
1227
  };
1205
1228
  source.addEventListener(event, listener);
1206
1229
  return () => {
@@ -1230,13 +1253,15 @@ function createWebSocket(url, options) {
1230
1253
  setStatus("open");
1231
1254
  reconnectCount = 0;
1232
1255
  };
1233
- socket.onmessage = (event) => {
1234
- let parsed;
1256
+ const parseMessage = options?.parse ?? ((raw) => {
1235
1257
  try {
1236
- parsed = JSON.parse(event.data);
1258
+ return JSON.parse(raw);
1237
1259
  } catch {
1238
- parsed = event.data;
1260
+ return raw;
1239
1261
  }
1262
+ });
1263
+ socket.onmessage = (event) => {
1264
+ const parsed = parseMessage(event.data);
1240
1265
  setData(parsed);
1241
1266
  for (const handler of handlers) {
1242
1267
  handler(parsed);
@@ -1349,6 +1374,10 @@ function applyRevalidation(revalidateData) {
1349
1374
  }
1350
1375
  }
1351
1376
  function enableAutoRevalidation() {
1377
+ if (typeof window === "undefined") {
1378
+ return () => {
1379
+ };
1380
+ }
1352
1381
  const handler = (event) => {
1353
1382
  const detail = event.detail;
1354
1383
  if (detail && typeof detail === "object") {
@@ -1417,9 +1446,10 @@ async function handleRPC(endpoint, body, revalidateData) {
1417
1446
  if (revalidateData) {
1418
1447
  return { data: result, __revalidate: revalidateData };
1419
1448
  }
1420
- return result;
1449
+ return { data: result };
1421
1450
  } catch (err) {
1422
- const message = err instanceof Error ? err.message : String(err);
1451
+ const isDev = typeof process !== "undefined" && process.env?.NODE_ENV === "development";
1452
+ const message = isDev && err instanceof Error ? err.message : "Internal server error";
1423
1453
  return { error: message };
1424
1454
  }
1425
1455
  }
@@ -1477,6 +1507,6 @@ async function renderIsland(slotsJson, islandId) {
1477
1507
  return wasm.render_island(ir, slotsJson, islandId);
1478
1508
  }
1479
1509
 
1480
- export { $, $$, $$serverFunction, activateIslands, addClass, applyRevalidation, children, closest, createAction, createBus, createContext, createErrorBoundary, createFetch, createHistory, createIndexedDB, createLocalStorage, createPortal, createRPCMiddleware, createSSE, createSessionStorage, createStore, createSuspense, createSwitch, createText, createWebSocket, defineComponent, delegate, disposeComponent, enableAutoRevalidation, fetchJSON, getRegisteredEndpoints, getServerFunction, handleRPC, inject, mount, nextSibling, onIntersect, onKey, onMount, onMutation, onResize, onUnmount, parent, persist, prevSibling, provide, registerResource, registerServerFunction, removeClass, renderIsland, renderLocal, setAttr, setHTML, setStyle, setText, siblings, toggleClass, trackDisposer, unprovide, unregisterResource, withRevalidation };
1510
+ export { $, $$, $$serverFunction, activateIslands, addClass, applyRevalidation, children, closest, createAction, createBus, createContext, createErrorBoundary, createFetch, createHistory, createIndexedDB, createLocalStorage, createPortal, createRPCMiddleware, createSSE, createSessionStorage, createStore, createSuspense, createSwitch, createText, createWebSocket, defineComponent, delegate, disposeComponent, enableAutoRevalidation, fetchJSON, getRegisteredEndpoints, getServerFunction, handleRPC, inject, mount, nextSibling, onIntersect, onKey, onMount, onMutation, onResize, onUnmount, parent, persist, prevSibling, provide, registerResource, registerServerFunction, removeClass, renderIsland, renderLocal, setAttr, setHTML, setHTMLUnsafe, setStyle, setText, siblings, toggleClass, trackDisposer, unprovide, unregisterResource, withRevalidation };
1481
1511
  //# sourceMappingURL=index.js.map
1482
1512
  //# sourceMappingURL=index.js.map