@getforma/core 0.3.0 → 0.6.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 (46) hide show
  1. package/README.md +201 -13
  2. package/dist/{chunk-KX5WRZH7.js → chunk-DPSAVBCP.js} +3 -4
  3. package/dist/chunk-DPSAVBCP.js.map +1 -0
  4. package/dist/{chunk-FPSLC62A.cjs → chunk-KH3F5NRU.cjs} +2 -4
  5. package/dist/chunk-KH3F5NRU.cjs.map +1 -0
  6. package/dist/{chunk-VKKPX4YU.js → chunk-TKGUHASG.js} +79 -19
  7. package/dist/chunk-TKGUHASG.js.map +1 -0
  8. package/dist/{chunk-VP5EOGM5.cjs → chunk-YSKF3VRA.cjs} +87 -26
  9. package/dist/chunk-YSKF3VRA.cjs.map +1 -0
  10. package/dist/forma-runtime-csp.js +2 -0
  11. package/dist/forma-runtime.js +2 -0
  12. package/dist/formajs-runtime-hardened.global.js +1 -1
  13. package/dist/formajs-runtime-hardened.global.js.map +1 -1
  14. package/dist/formajs-runtime.global.js +1 -1
  15. package/dist/formajs-runtime.global.js.map +1 -1
  16. package/dist/formajs.global.js +1 -1
  17. package/dist/formajs.global.js.map +1 -1
  18. package/dist/index.cjs +154 -96
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +83 -35
  21. package/dist/index.d.ts +83 -35
  22. package/dist/index.js +99 -40
  23. package/dist/index.js.map +1 -1
  24. package/dist/runtime-hardened.cjs +224 -60
  25. package/dist/runtime-hardened.cjs.map +1 -1
  26. package/dist/runtime-hardened.d.cts +86 -0
  27. package/dist/runtime-hardened.d.ts +86 -0
  28. package/dist/runtime-hardened.js +225 -61
  29. package/dist/runtime-hardened.js.map +1 -1
  30. package/dist/runtime.cjs +248 -83
  31. package/dist/runtime.cjs.map +1 -1
  32. package/dist/runtime.js +226 -61
  33. package/dist/runtime.js.map +1 -1
  34. package/dist/ssr/index.cjs +69 -73
  35. package/dist/ssr/index.cjs.map +1 -1
  36. package/dist/ssr/index.d.cts +4 -0
  37. package/dist/ssr/index.d.ts +4 -0
  38. package/dist/ssr/index.js +69 -73
  39. package/dist/ssr/index.js.map +1 -1
  40. package/dist/tc39-compat.cjs +3 -3
  41. package/dist/tc39-compat.js +1 -1
  42. package/package.json +24 -3
  43. package/dist/chunk-FPSLC62A.cjs.map +0 -1
  44. package/dist/chunk-KX5WRZH7.js.map +0 -1
  45. package/dist/chunk-VKKPX4YU.js.map +0 -1
  46. package/dist/chunk-VP5EOGM5.cjs.map +0 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
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';
3
- import { createSignal, createValueSignal } from './chunk-KX5WRZH7.js';
4
- export { createComputed, createSignal } from './chunk-KX5WRZH7.js';
1
+ import { internalEffect, createRoot, hydrateIsland, untrack, createEffect, pushSuspenseContext, popSuspenseContext, __DEV__, reportError, batch } from './chunk-TKGUHASG.js';
2
+ export { Fragment, batch, cleanup, createEffect, createList, createMemo, createReducer, createRef, createResource, createRoot, createShow, fragment, h, hydrateIsland, on, onCleanup, onError, reconcileList, untrack } from './chunk-TKGUHASG.js';
3
+ import { createSignal } from './chunk-DPSAVBCP.js';
4
+ export { createComputed, createSignal } from './chunk-DPSAVBCP.js';
5
5
 
6
6
  // src/dom/text.ts
7
7
  function createText(value) {
@@ -238,14 +238,11 @@ 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
- if (trigger === "interaction" || trigger === "idle") {
247
- console.warn(`[forma] Trigger "${trigger}" not yet implemented for island "${componentName}" (id=${id}), falling back to load`);
248
- }
249
246
  if (trigger === "visible") {
250
247
  const observer = new IntersectionObserver(
251
248
  (entries) => {
@@ -258,23 +255,52 @@ function activateIslands(registry2) {
258
255
  { rootMargin: "200px" }
259
256
  );
260
257
  observer.observe(root);
258
+ } else if (trigger === "idle") {
259
+ const hydrate = () => hydrateIslandRoot(root, id, componentName, hydrateFn, sharedProps);
260
+ if (typeof requestIdleCallback === "function") {
261
+ requestIdleCallback(hydrate);
262
+ } else {
263
+ setTimeout(hydrate, 200);
264
+ }
265
+ } else if (trigger === "interaction") {
266
+ const hydrate = () => {
267
+ root.removeEventListener("pointerdown", hydrate, true);
268
+ root.removeEventListener("focusin", hydrate, true);
269
+ hydrateIslandRoot(root, id, componentName, hydrateFn, sharedProps);
270
+ };
271
+ root.addEventListener("pointerdown", hydrate, { capture: true, once: true });
272
+ root.addEventListener("focusin", hydrate, { capture: true, once: true });
261
273
  } else {
262
274
  hydrateIslandRoot(root, id, componentName, hydrateFn, sharedProps);
263
275
  }
264
276
  }
265
277
  }
278
+ function deactivateIsland(el) {
279
+ const dispose = el.__formaDispose;
280
+ if (typeof dispose === "function") {
281
+ dispose();
282
+ delete el.__formaDispose;
283
+ el.setAttribute("data-forma-status", "disposed");
284
+ }
285
+ }
286
+ function deactivateAllIslands(root = document) {
287
+ const islands = root.querySelectorAll('[data-forma-status="active"]');
288
+ for (const island of islands) {
289
+ deactivateIsland(island);
290
+ }
291
+ }
266
292
  function hydrateIslandRoot(root, id, componentName, hydrateFn, sharedProps) {
267
293
  try {
268
294
  const props = loadIslandProps(root, id, sharedProps);
269
295
  root.setAttribute("data-forma-status", "hydrating");
270
296
  let activeRoot = root;
271
297
  createRoot((dispose) => {
272
- activeRoot = hydrateIsland(() => hydrateFn(props), root);
298
+ activeRoot = hydrateIsland(() => hydrateFn(root, props), root);
273
299
  activeRoot.__formaDispose = dispose;
274
300
  });
275
301
  activeRoot.setAttribute("data-forma-status", "active");
276
302
  } catch (err) {
277
- console.error(`[forma] Island "${componentName}" (id=${id}) failed:`, err);
303
+ if (__DEV__) console.error(`[forma] Island "${componentName}" (id=${id}) failed:`, err);
278
304
  root.setAttribute("data-forma-status", "error");
279
305
  }
280
306
  }
@@ -322,13 +348,15 @@ function defineComponent(setupOrDef) {
322
348
  for (const cb of ctx.unmountCallbacks) {
323
349
  try {
324
350
  cb();
325
- } catch {
351
+ } catch (e) {
352
+ reportError(e, "onUnmount");
326
353
  }
327
354
  }
328
355
  for (const d of ctx.disposers) {
329
356
  try {
330
357
  d();
331
- } catch {
358
+ } catch (e) {
359
+ reportError(e, "component disposer");
332
360
  }
333
361
  }
334
362
  ctx.disposers.length = 0;
@@ -342,7 +370,8 @@ function defineComponent(setupOrDef) {
342
370
  if (typeof cleanup2 === "function") {
343
371
  ctx.unmountCallbacks.push(cleanup2);
344
372
  }
345
- } catch {
373
+ } catch (e) {
374
+ reportError(e, "onMount");
346
375
  }
347
376
  }
348
377
  return dom;
@@ -616,9 +645,9 @@ function createHistory(source, options) {
616
645
  const maxLength = options?.maxLength ?? 100;
617
646
  let _stack = [sourceGet()];
618
647
  let _cursor = 0;
619
- const [stackSignal, setStackSignal] = createValueSignal([..._stack]);
620
- const [cursorSignal, setCursorSignal] = createValueSignal(_cursor);
621
- const [stackLenSignal, setStackLenSignal] = createValueSignal(_stack.length);
648
+ const [stackSignal, setStackSignal] = createSignal([..._stack]);
649
+ const [cursorSignal, setCursorSignal] = createSignal(_cursor);
650
+ const [stackLenSignal, setStackLenSignal] = createSignal(_stack.length);
622
651
  function syncSignals() {
623
652
  batch(() => {
624
653
  setStackSignal([..._stack]);
@@ -685,11 +714,14 @@ function persist(source, key, options) {
685
714
  const storage = options?.storage ?? globalThis.localStorage;
686
715
  const serialize = options?.serialize ?? JSON.stringify;
687
716
  const deserialize = options?.deserialize ?? JSON.parse;
717
+ const validate = options?.validate;
688
718
  try {
689
719
  const stored = storage.getItem(key);
690
720
  if (stored !== null) {
691
721
  const value = deserialize(stored);
692
- sourceSet(value);
722
+ if (!validate || validate(value)) {
723
+ sourceSet(value);
724
+ }
693
725
  }
694
726
  } catch {
695
727
  }
@@ -870,6 +902,9 @@ function setText(el, text) {
870
902
  function setHTML(el, html) {
871
903
  el.innerHTML = html;
872
904
  }
905
+ function setHTMLUnsafe(el, html) {
906
+ el.innerHTML = html;
907
+ }
873
908
 
874
909
  // src/dom-utils/traverse.ts
875
910
  function closest(el, selector) {
@@ -953,20 +988,26 @@ function onMutation(el, handler, options) {
953
988
  function createLocalStorage(key, options) {
954
989
  const serialize = options?.serialize ?? JSON.stringify;
955
990
  const deserialize = options?.deserialize ?? JSON.parse;
991
+ const validate = options?.validate;
956
992
  return {
957
993
  key,
958
994
  get() {
959
995
  try {
960
996
  const raw = localStorage.getItem(key);
961
997
  if (raw === null) return null;
962
- return deserialize(raw);
998
+ const value = deserialize(raw);
999
+ if (validate && !validate(value)) return null;
1000
+ return value;
963
1001
  } catch {
964
1002
  return null;
965
1003
  }
966
1004
  },
967
1005
  set(value) {
968
- const serialized = serialize(value);
969
- localStorage.setItem(key, serialized);
1006
+ try {
1007
+ const serialized = serialize(value);
1008
+ localStorage.setItem(key, serialized);
1009
+ } catch {
1010
+ }
970
1011
  },
971
1012
  remove() {
972
1013
  localStorage.removeItem(key);
@@ -978,20 +1019,26 @@ function createLocalStorage(key, options) {
978
1019
  function createSessionStorage(key, options) {
979
1020
  const serialize = options?.serialize ?? JSON.stringify;
980
1021
  const deserialize = options?.deserialize ?? JSON.parse;
1022
+ const validate = options?.validate;
981
1023
  return {
982
1024
  key,
983
1025
  get() {
984
1026
  try {
985
1027
  const raw = sessionStorage.getItem(key);
986
1028
  if (raw === null) return null;
987
- return deserialize(raw);
1029
+ const value = deserialize(raw);
1030
+ if (validate && !validate(value)) return null;
1031
+ return value;
988
1032
  } catch {
989
1033
  return null;
990
1034
  }
991
1035
  },
992
1036
  set(value) {
993
- const serialized = serialize(value);
994
- sessionStorage.setItem(key, serialized);
1037
+ try {
1038
+ const serialized = serialize(value);
1039
+ sessionStorage.setItem(key, serialized);
1040
+ } catch {
1041
+ }
995
1042
  },
996
1043
  remove() {
997
1044
  sessionStorage.removeItem(key);
@@ -1122,7 +1169,7 @@ function createFetch(url, options) {
1122
1169
  const transformed = transform ? transform(json) : json;
1123
1170
  setData(transformed);
1124
1171
  } catch (err) {
1125
- if (err?.name === "AbortError") {
1172
+ if (err instanceof Error && err.name === "AbortError") {
1126
1173
  return;
1127
1174
  }
1128
1175
  setError(err instanceof Error ? err : new Error(String(err)));
@@ -1174,13 +1221,15 @@ function createSSE(url, options) {
1174
1221
  setConnected(true);
1175
1222
  setError(null);
1176
1223
  };
1177
- source.onmessage = (event) => {
1224
+ const parseMessage = options?.parse ?? ((raw) => {
1178
1225
  try {
1179
- const parsed = JSON.parse(event.data);
1180
- setData(parsed);
1226
+ return JSON.parse(raw);
1181
1227
  } catch {
1182
- setData(event.data);
1228
+ return raw;
1183
1229
  }
1230
+ });
1231
+ source.onmessage = (event) => {
1232
+ setData(parseMessage(event.data));
1184
1233
  };
1185
1234
  source.onerror = (event) => {
1186
1235
  setError(event);
@@ -1195,12 +1244,15 @@ function createSSE(url, options) {
1195
1244
  setConnected(false);
1196
1245
  },
1197
1246
  on(event, handler) {
1198
- const listener = (e) => {
1247
+ const parseEvent = options?.parse ?? ((raw) => {
1199
1248
  try {
1200
- handler(JSON.parse(e.data));
1249
+ return JSON.parse(raw);
1201
1250
  } catch {
1202
- handler(e.data);
1251
+ return raw;
1203
1252
  }
1253
+ });
1254
+ const listener = (e) => {
1255
+ handler(parseEvent(e.data));
1204
1256
  };
1205
1257
  source.addEventListener(event, listener);
1206
1258
  return () => {
@@ -1230,13 +1282,15 @@ function createWebSocket(url, options) {
1230
1282
  setStatus("open");
1231
1283
  reconnectCount = 0;
1232
1284
  };
1233
- socket.onmessage = (event) => {
1234
- let parsed;
1285
+ const parseMessage = options?.parse ?? ((raw) => {
1235
1286
  try {
1236
- parsed = JSON.parse(event.data);
1287
+ return JSON.parse(raw);
1237
1288
  } catch {
1238
- parsed = event.data;
1289
+ return raw;
1239
1290
  }
1291
+ });
1292
+ socket.onmessage = (event) => {
1293
+ const parsed = parseMessage(event.data);
1240
1294
  setData(parsed);
1241
1295
  for (const handler of handlers) {
1242
1296
  handler(parsed);
@@ -1290,8 +1344,8 @@ function createWebSocket(url, options) {
1290
1344
 
1291
1345
  // src/server/action.ts
1292
1346
  function createAction(serverFn, options) {
1293
- const [pending, setPending] = createValueSignal(false);
1294
- const [error, setError] = createValueSignal(void 0);
1347
+ const [pending, setPending] = createSignal(false);
1348
+ const [error, setError] = createSignal(void 0);
1295
1349
  const action = async (...args) => {
1296
1350
  setPending(true);
1297
1351
  setError(void 0);
@@ -1349,6 +1403,10 @@ function applyRevalidation(revalidateData) {
1349
1403
  }
1350
1404
  }
1351
1405
  function enableAutoRevalidation() {
1406
+ if (typeof window === "undefined") {
1407
+ return () => {
1408
+ };
1409
+ }
1352
1410
  const handler = (event) => {
1353
1411
  const detail = event.detail;
1354
1412
  if (detail && typeof detail === "object") {
@@ -1417,9 +1475,10 @@ async function handleRPC(endpoint, body, revalidateData) {
1417
1475
  if (revalidateData) {
1418
1476
  return { data: result, __revalidate: revalidateData };
1419
1477
  }
1420
- return result;
1478
+ return { data: result };
1421
1479
  } catch (err) {
1422
- const message = err instanceof Error ? err.message : String(err);
1480
+ const isDev = typeof process !== "undefined" && process.env?.NODE_ENV === "development";
1481
+ const message = isDev && err instanceof Error ? err.message : "Internal server error";
1423
1482
  return { error: message };
1424
1483
  }
1425
1484
  }
@@ -1477,6 +1536,6 @@ async function renderIsland(slotsJson, islandId) {
1477
1536
  return wasm.render_island(ir, slotsJson, islandId);
1478
1537
  }
1479
1538
 
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 };
1539
+ export { $, $$, $$serverFunction, activateIslands, addClass, applyRevalidation, children, closest, createAction, createBus, createContext, createErrorBoundary, createFetch, createHistory, createIndexedDB, createLocalStorage, createPortal, createRPCMiddleware, createSSE, createSessionStorage, createStore, createSuspense, createSwitch, createText, createWebSocket, deactivateAllIslands, deactivateIsland, 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
1540
  //# sourceMappingURL=index.js.map
1482
1541
  //# sourceMappingURL=index.js.map