fynixui 1.0.10 → 1.0.12

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 (104) hide show
  1. package/dist/custom/DataTable.js +1 -0
  2. package/dist/custom/button.js +241 -1
  3. package/dist/custom/index.js +1 -1
  4. package/dist/error/errorOverlay.js +1 -1
  5. package/dist/hooks/nixFor.js +6 -4
  6. package/dist/package.json +34 -37
  7. package/dist/plugins/vite-plugin-res.js +26 -4
  8. package/dist/router/router.js +108 -217
  9. package/dist/runtime.js +1251 -1028
  10. package/{dist → dist-types}/context/context.d.ts +1 -2
  11. package/dist-types/custom/DataTable.d.ts +0 -0
  12. package/dist-types/custom/button.d.ts +35 -0
  13. package/dist-types/custom/index.d.ts +2 -0
  14. package/{dist → dist-types}/custom/path.d.ts +0 -1
  15. package/{dist → dist-types}/error/errorOverlay.d.ts +0 -1
  16. package/{dist → dist-types}/fynix/index.d.ts +0 -1
  17. package/{dist → dist-types}/hooks/nixAsync.d.ts +0 -1
  18. package/{dist → dist-types}/hooks/nixAsyncCache.d.ts +0 -1
  19. package/{dist → dist-types}/hooks/nixAsyncDebounce.d.ts +0 -1
  20. package/{dist → dist-types}/hooks/nixAsyncQuery.d.ts +0 -1
  21. package/{dist → dist-types}/hooks/nixCallback.d.ts +0 -1
  22. package/{dist → dist-types}/hooks/nixComputed.d.ts +0 -1
  23. package/{dist → dist-types}/hooks/nixDebounce.d.ts +0 -1
  24. package/{dist → dist-types}/hooks/nixEffect.d.ts +0 -1
  25. package/{dist → dist-types}/hooks/nixFor.d.ts +0 -1
  26. package/{dist → dist-types}/hooks/nixForm.d.ts +0 -1
  27. package/{dist → dist-types}/hooks/nixFormAsync.d.ts +0 -1
  28. package/{dist → dist-types}/hooks/nixInterval.d.ts +0 -1
  29. package/{dist → dist-types}/hooks/nixLazy.d.ts +0 -1
  30. package/{dist → dist-types}/hooks/nixLazyAsync.d.ts +0 -1
  31. package/{dist → dist-types}/hooks/nixLazyFormAsync.d.ts +0 -1
  32. package/{dist → dist-types}/hooks/nixLocalStorage.d.ts +0 -1
  33. package/{dist → dist-types}/hooks/nixMemo.d.ts +0 -1
  34. package/{dist → dist-types}/hooks/nixPrevious.d.ts +0 -1
  35. package/{dist → dist-types}/hooks/nixRef.d.ts +0 -1
  36. package/{dist → dist-types}/hooks/nixState.d.ts +0 -1
  37. package/{dist → dist-types}/hooks/nixStore.d.ts +0 -1
  38. package/{dist → dist-types}/plugins/vite-plugin-res.d.ts +0 -1
  39. package/{dist → dist-types}/router/router.d.ts +14 -11
  40. package/dist-types/runtime.d.ts +200 -0
  41. package/package.json +43 -41
  42. package/dist/context/context.d.ts.map +0 -1
  43. package/dist/context/context.js.map +0 -7
  44. package/dist/custom/button.d.ts +0 -2
  45. package/dist/custom/button.d.ts.map +0 -1
  46. package/dist/custom/button.js.map +0 -7
  47. package/dist/custom/index.d.ts +0 -3
  48. package/dist/custom/index.d.ts.map +0 -1
  49. package/dist/custom/index.js.map +0 -7
  50. package/dist/custom/path.d.ts.map +0 -1
  51. package/dist/custom/path.js.map +0 -7
  52. package/dist/error/errorOverlay.d.ts.map +0 -1
  53. package/dist/error/errorOverlay.js.map +0 -7
  54. package/dist/fynix/index.d.ts.map +0 -1
  55. package/dist/fynix/index.js.map +0 -7
  56. package/dist/hooks/nixAsync.d.ts.map +0 -1
  57. package/dist/hooks/nixAsync.js.map +0 -7
  58. package/dist/hooks/nixAsyncCache.d.ts.map +0 -1
  59. package/dist/hooks/nixAsyncCache.js.map +0 -7
  60. package/dist/hooks/nixAsyncDebounce.d.ts.map +0 -1
  61. package/dist/hooks/nixAsyncDebounce.js.map +0 -7
  62. package/dist/hooks/nixAsyncQuery.d.ts.map +0 -1
  63. package/dist/hooks/nixAsyncQuery.js.map +0 -7
  64. package/dist/hooks/nixCallback.d.ts.map +0 -1
  65. package/dist/hooks/nixCallback.js.map +0 -7
  66. package/dist/hooks/nixComputed.d.ts.map +0 -1
  67. package/dist/hooks/nixComputed.js.map +0 -7
  68. package/dist/hooks/nixDebounce.d.ts.map +0 -1
  69. package/dist/hooks/nixDebounce.js.map +0 -7
  70. package/dist/hooks/nixEffect.d.ts.map +0 -1
  71. package/dist/hooks/nixEffect.js.map +0 -7
  72. package/dist/hooks/nixFor.d.ts.map +0 -1
  73. package/dist/hooks/nixFor.js.map +0 -7
  74. package/dist/hooks/nixForm.d.ts.map +0 -1
  75. package/dist/hooks/nixForm.js.map +0 -7
  76. package/dist/hooks/nixFormAsync.d.ts.map +0 -1
  77. package/dist/hooks/nixFormAsync.js.map +0 -7
  78. package/dist/hooks/nixInterval.d.ts.map +0 -1
  79. package/dist/hooks/nixInterval.js.map +0 -7
  80. package/dist/hooks/nixLazy.d.ts.map +0 -1
  81. package/dist/hooks/nixLazy.js.map +0 -7
  82. package/dist/hooks/nixLazyAsync.d.ts.map +0 -1
  83. package/dist/hooks/nixLazyAsync.js.map +0 -7
  84. package/dist/hooks/nixLazyFormAsync.d.ts.map +0 -1
  85. package/dist/hooks/nixLazyFormAsync.js.map +0 -7
  86. package/dist/hooks/nixLocalStorage.d.ts.map +0 -1
  87. package/dist/hooks/nixLocalStorage.js.map +0 -7
  88. package/dist/hooks/nixMemo.d.ts.map +0 -1
  89. package/dist/hooks/nixMemo.js.map +0 -7
  90. package/dist/hooks/nixPrevious.d.ts.map +0 -1
  91. package/dist/hooks/nixPrevious.js.map +0 -7
  92. package/dist/hooks/nixRef.d.ts.map +0 -1
  93. package/dist/hooks/nixRef.js.map +0 -7
  94. package/dist/hooks/nixState.d.ts.map +0 -1
  95. package/dist/hooks/nixState.js.map +0 -7
  96. package/dist/hooks/nixStore.d.ts.map +0 -1
  97. package/dist/hooks/nixStore.js.map +0 -7
  98. package/dist/plugins/vite-plugin-res.d.ts.map +0 -1
  99. package/dist/plugins/vite-plugin-res.js.map +0 -7
  100. package/dist/router/router.d.ts.map +0 -1
  101. package/dist/router/router.js.map +0 -7
  102. package/dist/runtime.d.ts +0 -124
  103. package/dist/runtime.d.ts.map +0 -1
  104. package/dist/runtime.js.map +0 -7
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixEffect.ts"],
4
- "sourcesContent": ["/* MIT License\r\n\r\n* Copyright (c) 2026 Resty Gonzales\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n* SOFTWARE.\r\n */\r\n/* ----------------------\r\n nixEffect - Side Effects Hook\r\n Memory Leaks & Security Issues Resolved\r\n---------------------- */\r\nimport { activeContext } from \"../context/context\";\r\n\r\n/**\r\n * Execute side effects in a component with automatic cleanup and security enhancements.\r\n * Similar to React's useEffect but with enhanced security and memory leak prevention.\r\n *\r\n * @param {() => (void | (() => void))} effect - Effect function, optionally returns cleanup function\r\n * @param {Array<any>} [deps=[]] - Dependency array. Effect re-runs when dependencies change.\r\n * @param {object} [options={}] - Configuration options\r\n *\r\n * @example\r\n * // Run once on mount\r\n * nixEffect(() => {\r\n * console.log('Component mounted');\r\n * return () => console.log('Component unmounted');\r\n * }, []);\r\n *\r\n * @example\r\n * // Run when count changes with timeout\r\n * const count = nixState(0);\r\n * nixEffect(() => {\r\n * console.log('Count is:', count.value);\r\n * }, [count.value], { timeout: 5000 });\r\n *\r\n * @example\r\n * // Timer with cleanup\r\n * nixEffect(() => {\r\n * const timer = setInterval(() => console.log('tick'), 1000);\r\n * return () => clearInterval(timer);\r\n * }, []);\r\n *\r\n * @example\r\n * // Event listener with cleanup\r\n * nixEffect(() => {\r\n * const handler = (e) => console.log('clicked', e);\r\n * document.addEventListener('click', handler);\r\n * return () => document.removeEventListener('click', handler);\r\n * }, []);\r\n *\r\n * @throws {Error} If called outside a component context\r\n */\r\nexport function nixEffect(\r\n effect: () => void | (() => void),\r\n deps: any[] = []\r\n): void {\r\n const ctx = activeContext as\r\n | (typeof activeContext & {\r\n hookIndex: number;\r\n hooks: Array<any>;\r\n cleanups?: Array<() => void>;\r\n })\r\n | undefined;\r\n if (!ctx) throw new Error(\"nixEffect() called outside component\");\r\n\r\n if (typeof effect !== \"function\") {\r\n console.error(\"[nixEffect] First argument must be a function\");\r\n return;\r\n }\r\n if (!Array.isArray(deps)) {\r\n console.error(\"[nixEffect] Second argument must be an array\");\r\n deps = [];\r\n }\r\n const MAX_DEPS = 100;\r\n if (deps.length > MAX_DEPS) {\r\n console.warn(\r\n `[nixEffect] Dependency array too large (${deps.length}). Limited to ${MAX_DEPS}.`\r\n );\r\n deps = deps.slice(0, MAX_DEPS);\r\n }\r\n const idx = ctx.hookIndex++;\r\n const prev = ctx.hooks[idx];\r\n const hasChanged = !prev || !shallowArrayEqual(prev.deps, deps);\r\n if (hasChanged) {\r\n if (prev?.cleanup) {\r\n try {\r\n if (typeof prev.cleanup === \"function\") {\r\n prev.cleanup();\r\n }\r\n } catch (err) {\r\n console.error(\"[nixEffect] Cleanup error:\", err);\r\n }\r\n }\r\n let cleanup: void | (() => void);\r\n try {\r\n cleanup = effect();\r\n if (cleanup !== undefined && typeof cleanup !== \"function\") {\r\n console.warn(\r\n \"[nixEffect] Effect should return undefined or a cleanup function\"\r\n );\r\n cleanup = undefined;\r\n }\r\n } catch (err) {\r\n console.error(\"[nixEffect] Effect error:\", err);\r\n cleanup = undefined;\r\n }\r\n ctx.hooks[idx] = { deps, cleanup };\r\n if (cleanup && typeof cleanup === \"function\") {\r\n if (!ctx.cleanups) ctx.cleanups = [];\r\n ctx.cleanups.push(cleanup);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Shallow comparison of two arrays for dependency checking.\r\n * More reliable and secure than JSON.stringify.\r\n *\r\n * @param {Array<any>} arr1 - First array\r\n * @param {Array<any>} arr2 - Second array\r\n * @returns {boolean} True if arrays are shallowly equal\r\n */\r\nfunction shallowArrayEqual(arr1: any[], arr2: any[]): boolean {\r\n if (arr1.length !== arr2.length) return false;\r\n for (let i = 0; i < arr1.length; i++) {\r\n if (!Object.is(arr1[i], arr2[i])) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n}\r\n\r\n/**\r\n * Run an effect only once on component mount.\r\n * Convenience wrapper around nixEffect.\r\n *\r\n * @param {() => (void | (() => void))} effect - Effect function\r\n *\r\n * @example\r\n * nixEffectOnce(() => {\r\n * console.log('Mounted');\r\n * return () => console.log('Unmounted');\r\n * });\r\n */\r\nexport function nixEffectOnce(effect: () => void | (() => void)): void {\r\n return nixEffect(effect, []);\r\n}\r\n\r\n/**\r\n * Run an effect every time the component renders.\r\n * Use with caution - can cause performance issues.\r\n *\r\n * @param {() => (void | (() => void))} effect - Effect function\r\n *\r\n * @example\r\n * nixEffectAlways(() => {\r\n * console.log('Component rendered');\r\n * });\r\n */\r\nexport function nixEffectAlways(effect: () => void | (() => void)): void {\r\n const ctx = activeContext as\r\n | (typeof activeContext & { version: any })\r\n | undefined;\r\n if (!ctx) throw new Error(\"nixEffectAlways() called outside component\");\r\n if (typeof effect !== \"function\") {\r\n console.error(\"[nixEffectAlways] Argument must be a function\");\r\n return;\r\n }\r\n return nixEffect(effect, [ctx.version]);\r\n}\r\n"],
5
- "mappings": ";;AA0BA,SAAS,qBAAqB;AAyCvB,SAAS,UACd,QACA,OAAc,CAAC,GACT;AACN,QAAM,MAAM;AAOZ,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,sCAAsC;AAEhE,MAAI,OAAO,WAAW,YAAY;AAChC,YAAQ,MAAM,+CAA+C;AAC7D;AAAA,EACF;AACA,MAAI,CAAC,MAAM,QAAQ,IAAI,GAAG;AACxB,YAAQ,MAAM,8CAA8C;AAC5D,WAAO,CAAC;AAAA,EACV;AACA,QAAM,WAAW;AACjB,MAAI,KAAK,SAAS,UAAU;AAC1B,YAAQ;AAAA,MACN,2CAA2C,KAAK,MAAM,iBAAiB,QAAQ;AAAA,IACjF;AACA,WAAO,KAAK,MAAM,GAAG,QAAQ;AAAA,EAC/B;AACA,QAAM,MAAM,IAAI;AAChB,QAAM,OAAO,IAAI,MAAM,GAAG;AAC1B,QAAM,aAAa,CAAC,QAAQ,CAAC,kBAAkB,KAAK,MAAM,IAAI;AAC9D,MAAI,YAAY;AACd,QAAI,MAAM,SAAS;AACjB,UAAI;AACF,YAAI,OAAO,KAAK,YAAY,YAAY;AACtC,eAAK,QAAQ;AAAA,QACf;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,MAAM,8BAA8B,GAAG;AAAA,MACjD;AAAA,IACF;AACA,QAAI;AACJ,QAAI;AACF,gBAAU,OAAO;AACjB,UAAI,YAAY,UAAa,OAAO,YAAY,YAAY;AAC1D,gBAAQ;AAAA,UACN;AAAA,QACF;AACA,kBAAU;AAAA,MACZ;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,MAAM,6BAA6B,GAAG;AAC9C,gBAAU;AAAA,IACZ;AACA,QAAI,MAAM,GAAG,IAAI,EAAE,MAAM,QAAQ;AACjC,QAAI,WAAW,OAAO,YAAY,YAAY;AAC5C,UAAI,CAAC,IAAI,SAAU,KAAI,WAAW,CAAC;AACnC,UAAI,SAAS,KAAK,OAAO;AAAA,IAC3B;AAAA,EACF;AACF;AA5DgB;AAsEhB,SAAS,kBAAkB,MAAa,MAAsB;AAC5D,MAAI,KAAK,WAAW,KAAK,OAAQ,QAAO;AACxC,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,CAAC,OAAO,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG;AAChC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AARS;AAsBF,SAAS,cAAc,QAAyC;AACrE,SAAO,UAAU,QAAQ,CAAC,CAAC;AAC7B;AAFgB;AAeT,SAAS,gBAAgB,QAAyC;AACvE,QAAM,MAAM;AAGZ,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,4CAA4C;AACtE,MAAI,OAAO,WAAW,YAAY;AAChC,YAAQ,MAAM,+CAA+C;AAC7D;AAAA,EACF;AACA,SAAO,UAAU,QAAQ,CAAC,IAAI,OAAO,CAAC;AACxC;AAVgB;",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"nixFor.d.ts","sourceRoot":"","sources":["../../hooks/nixFor.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAErC,UAAU,aAAa,CAAC,CAAC;IACrB,KAAK,EAAE,CAAC,CAAC;IACT,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACvD;AAED,UAAU,QAAQ,CAAC,CAAC;IAChB,IAAI,EAAE,CAAC,EAAE,GAAG,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC,EAAE,CAAC;CAC1F;AAkBD,wBAAgB,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,CAoDhD"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixFor.ts"],
4
- "sourcesContent": ["/* MIT License\r\n* Copyright (c) 2026 Resty Gonzales\r\n*/\r\n\r\nimport { Fragment } from \"../runtime\";\r\nimport { VNode } from \"../types/fnx\";\r\n\r\ninterface ReactiveState<T> {\r\n value: T;\r\n _isNixState: boolean;\r\n subscribe(callback: (value: T) => void): () => void;\r\n}\r\n\r\ninterface ForProps<T> {\r\n each: T[] | ReactiveState<T[]>;\r\n children?: ((item: T, index: number) => VNode) | ((item: T, index: number) => VNode)[];\r\n}\r\n\r\n/**\r\n * <For> Component\r\n *\r\n * A reactive list iteration component that efficiently renders items from an array or reactive state.\r\n *\r\n * @example\r\n * ```tsx\r\n * <For each={items}>\r\n * {(item, index) => <div key={index}>{item.name}</div>}\r\n * </For>\r\n * ```\r\n *\r\n * @param props - Component properties\r\n * @param props.each - The array or reactive state of array to iterate over\r\n * @param props.children - Render function that receives (item, index) and returns a VNode\r\n */\r\nexport function For<T>(props: ForProps<T>): VNode {\r\n // Extract items from reactive state or plain array\r\n let items: T[] = [];\r\n\r\n if (props.each && typeof props.each === \"object\" && \"_isNixState\" in props.each) {\r\n // Access .value to subscribe to reactive state\r\n items = (props.each as ReactiveState<T[]>).value;\r\n } else if (Array.isArray(props.each)) {\r\n items = props.each;\r\n }\r\n\r\n // Get the renderer function\r\n // In Fynix's JSX transform, children passed as {() => ...} becomes props.children directly\r\n let renderer: ((item: T, index: number) => VNode) | undefined;\r\n\r\n // Handle both direct function and array of children (depends on JSX transform)\r\n if (typeof props.children === \"function\") {\r\n renderer = props.children;\r\n } else if (Array.isArray(props.children)) {\r\n // If JSX transform wraps it in an array, get first element\r\n const firstChild = props.children[0];\r\n if (typeof firstChild === \"function\") {\r\n renderer = firstChild as (item: T, index: number) => VNode;\r\n }\r\n }\r\n\r\n if (!renderer) {\r\n if (items.length > 0) {\r\n console.warn(\"[Fynix] <For> expects a function as its child. Received:\", typeof props.children);\r\n }\r\n return { type: Fragment, props: { children: [] }, key: null };\r\n }\r\n\r\n // Map items to VNodes\r\n const mapped = items.map((item, index) => {\r\n try {\r\n return renderer!(item, index);\r\n } catch (error) {\r\n console.error(`[Fynix] Error rendering item at index ${index}:`, error);\r\n // Return a safe fallback\r\n return {\r\n type: \"div\",\r\n props: {\r\n children: [\"Error rendering item\"],\r\n style: \"color: red;\"\r\n },\r\n key: index\r\n } as VNode;\r\n }\r\n });\r\n\r\n return { type: Fragment, props: { children: mapped }, key: null };\r\n}"],
5
- "mappings": ";;AAIA,SAAS,gBAAgB;AA8BlB,SAAS,IAAO,OAA2B;AAE9C,MAAI,QAAa,CAAC;AAElB,MAAI,MAAM,QAAQ,OAAO,MAAM,SAAS,YAAY,iBAAiB,MAAM,MAAM;AAE7E,YAAS,MAAM,KAA4B;AAAA,EAC/C,WAAW,MAAM,QAAQ,MAAM,IAAI,GAAG;AAClC,YAAQ,MAAM;AAAA,EAClB;AAIA,MAAI;AAGJ,MAAI,OAAO,MAAM,aAAa,YAAY;AACtC,eAAW,MAAM;AAAA,EACrB,WAAW,MAAM,QAAQ,MAAM,QAAQ,GAAG;AAEtC,UAAM,aAAa,MAAM,SAAS,CAAC;AACnC,QAAI,OAAO,eAAe,YAAY;AAClC,iBAAW;AAAA,IACf;AAAA,EACJ;AAEA,MAAI,CAAC,UAAU;AACX,QAAI,MAAM,SAAS,GAAG;AAClB,cAAQ,KAAK,4DAA4D,OAAO,MAAM,QAAQ;AAAA,IAClG;AACA,WAAO,EAAE,MAAM,UAAU,OAAO,EAAE,UAAU,CAAC,EAAE,GAAG,KAAK,KAAK;AAAA,EAChE;AAGA,QAAM,SAAS,MAAM,IAAI,CAAC,MAAM,UAAU;AACtC,QAAI;AACA,aAAO,SAAU,MAAM,KAAK;AAAA,IAChC,SAAS,OAAO;AACZ,cAAQ,MAAM,yCAAyC,KAAK,KAAK,KAAK;AAEtE,aAAO;AAAA,QACH,MAAM;AAAA,QACN,OAAO;AAAA,UACH,UAAU,CAAC,sBAAsB;AAAA,UACjC,OAAO;AAAA,QACX;AAAA,QACA,KAAK;AAAA,MACT;AAAA,IACJ;AAAA,EACJ,CAAC;AAED,SAAO,EAAE,MAAM,UAAU,OAAO,EAAE,UAAU,OAAO,GAAG,KAAK,KAAK;AACpE;AApDgB;",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"nixForm.d.ts","sourceRoot":"","sources":["../../hooks/nixForm.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,KAAK,cAAc,CAAC,CAAC,IAAI;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,KAAK,eAAe,CAAC,CAAC,IAAI;KACvB,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;CACnC,CAAC;AAEF,KAAK,SAAS,CAAC,CAAC,IAAI;IAClB,MAAM,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACtE,OAAO,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACxE,YAAY,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IACnD,OAAO,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IACvD,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IACzC,YAAY,EAAE,CACZ,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,KACxD,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK;QACrC,KAAK,EAAE,GAAG,CAAC;QACX,SAAS,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;QAC5B,QAAQ,EAAE,MAAM,IAAI,CAAC;KACtB,CAAC;CACH,CAAC;AAgBF,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzE,aAAa,GAAE,CAAW,EAC1B,eAAe,GAAE,eAAe,CAAC,CAAC,CAA4B,GAC7D,SAAS,CAAC,CAAC,CAAC,CA2Id"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixForm.ts"],
4
- "sourcesContent": ["/* MIT License\r\n\r\n* Copyright (c) 2026 Resty Gonzales\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n* SOFTWARE.\r\n */\r\n// core/hooks/nixForm.js - Form handling utilities with memory-safe async support\r\nimport { nixComputed } from \"./nixComputed.js\";\r\nimport { nixState } from \"./nixState.js\";\r\n\r\ntype ValidationRule<T> = {\r\n required?: boolean;\r\n minLength?: number;\r\n maxLength?: number;\r\n pattern?: RegExp;\r\n custom?: (value: any, values: T) => boolean;\r\n message?: string;\r\n};\r\n\r\ntype ValidationRules<T> = {\r\n [K in keyof T]?: ValidationRule<T>;\r\n};\r\n\r\ntype FormState<T> = {\r\n values: ReturnType<typeof nixState<T>>;\r\n errors: ReturnType<typeof nixState<Partial<Record<keyof T, string>>>>;\r\n touched: ReturnType<typeof nixState<Partial<Record<keyof T, boolean>>>>;\r\n isSubmitting: ReturnType<typeof nixState<boolean>>;\r\n isValid: ReturnType<typeof nixComputed<boolean>>;\r\n handleChange: (fieldName: keyof T, value: any) => void;\r\n handleBlur: (fieldName: keyof T) => void;\r\n handleSubmit: (\r\n onSubmit: (values: T, signal: AbortSignal) => Promise<void>\r\n ) => Promise<void>;\r\n cancelSubmit: () => void;\r\n reset: () => void;\r\n getFieldProps: (fieldName: keyof T) => {\r\n value: any;\r\n \"r-input\": (e: any) => void;\r\n \"r-blur\": () => void;\r\n };\r\n};\r\n\r\n/**\r\n * Reactive form handler with validation, reactive state, and safe async submit.\r\n *\r\n * @param {Object} [initialValues={}] - Initial values for form fields.\r\n * @param {Object} [validationRules={}] - Validation rules for fields.\r\n * @returns {Object} Form utilities: values, errors, touched, isSubmitting, isValid,\r\n * handleChange, handleBlur, handleSubmit, reset, getFieldProps, cancelSubmit\r\n *\r\n * @example\r\n * const form = nixForm({ email: \"\" }, {\r\n * email: { required: true, pattern: /^\\S+@\\S+$/, message: \"Invalid email\" }\r\n * });\r\n * form.handleSubmit(async (values) => { await api.submit(values); });\r\n */\r\nexport function nixForm<T extends Record<string, any> = Record<string, any>>(\r\n initialValues: T = {} as T,\r\n validationRules: ValidationRules<T> = {} as ValidationRules<T>\r\n): FormState<T> {\r\n const values = nixState<T>({ ...initialValues });\r\n const errors = nixState<Partial<Record<keyof T, string>>>({});\r\n const touched = nixState<Partial<Record<keyof T, boolean>>>({});\r\n const isSubmitting = nixState<boolean>(false);\r\n\r\n const isValid = nixComputed<boolean>(\r\n () => Object.keys(errors.value).length === 0\r\n );\r\n\r\n let abortController: AbortController | null = null;\r\n\r\n function validate(fieldName: keyof T, value: any): string | null {\r\n const rules = validationRules[fieldName];\r\n if (!rules) return null;\r\n\r\n if (rules.required && !value) {\r\n return rules.message || `${String(fieldName)} is required`;\r\n }\r\n if (rules.minLength && value.length < rules.minLength) {\r\n return (\r\n rules.message ||\r\n `${String(fieldName)} must be at least ${rules.minLength} characters`\r\n );\r\n }\r\n if (rules.maxLength && value.length > rules.maxLength) {\r\n return (\r\n rules.message ||\r\n `${String(fieldName)} must be at most ${rules.maxLength} characters`\r\n );\r\n }\r\n if (rules.pattern && !rules.pattern.test(value)) {\r\n return rules.message || `${String(fieldName)} is invalid`;\r\n }\r\n if (rules.custom && !rules.custom(value, values.value)) {\r\n return rules.message || `${String(fieldName)} is invalid`;\r\n }\r\n return null;\r\n }\r\n\r\n function handleChange(fieldName: keyof T, value: any): void {\r\n values.value = { ...values.value, [fieldName]: value };\r\n\r\n if (touched.value[fieldName]) {\r\n const error = validate(fieldName, value);\r\n if (error) {\r\n errors.value = { ...errors.value, [fieldName]: error };\r\n } else {\r\n const newErrors = { ...errors.value };\r\n delete newErrors[fieldName];\r\n errors.value = newErrors;\r\n }\r\n }\r\n }\r\n\r\n function handleBlur(fieldName: keyof T): void {\r\n touched.value = { ...touched.value, [fieldName]: true };\r\n const error = validate(fieldName, values.value[fieldName]);\r\n if (error) {\r\n errors.value = { ...errors.value, [fieldName]: error };\r\n }\r\n }\r\n\r\n function validateAll(): boolean {\r\n const newErrors: Partial<Record<keyof T, string>> = {};\r\n (Object.keys(validationRules) as Array<keyof T>).forEach((fieldName) => {\r\n const error = validate(fieldName, values.value[fieldName]);\r\n if (error) newErrors[fieldName] = error;\r\n });\r\n errors.value = newErrors;\r\n return Object.keys(newErrors).length === 0;\r\n }\r\n\r\n async function handleSubmit(\r\n onSubmit: (values: T, signal: AbortSignal) => Promise<void>\r\n ): Promise<void> {\r\n const allTouched = (Object.keys(validationRules) as Array<keyof T>).reduce(\r\n (acc, key) => {\r\n acc[key] = true;\r\n return acc;\r\n },\r\n {} as Partial<Record<keyof T, boolean>>\r\n );\r\n touched.value = allTouched;\r\n\r\n if (!validateAll()) return;\r\n\r\n if (abortController) abortController.abort();\r\n abortController = new AbortController();\r\n const signal = abortController.signal;\r\n\r\n isSubmitting.value = true;\r\n try {\r\n await onSubmit(values.value, signal);\r\n } catch (err: any) {\r\n if (err.name !== \"AbortError\") {\r\n console.error(\"[nixForm] Submission error:\", err);\r\n }\r\n } finally {\r\n if (!signal.aborted) isSubmitting.value = false;\r\n }\r\n }\r\n\r\n function cancelSubmit(): void {\r\n if (abortController) {\r\n abortController.abort();\r\n abortController = null;\r\n }\r\n }\r\n\r\n function reset(): void {\r\n values.value = { ...initialValues };\r\n errors.value = {};\r\n touched.value = {};\r\n isSubmitting.value = false;\r\n cancelSubmit();\r\n }\r\n\r\n function getFieldProps(fieldName: keyof T) {\r\n return {\r\n value: values.value[fieldName] || \"\",\r\n \"r-input\": (e: any) => handleChange(fieldName, e.target.value),\r\n \"r-blur\": () => handleBlur(fieldName),\r\n };\r\n }\r\n\r\n return {\r\n values,\r\n errors,\r\n touched,\r\n isSubmitting,\r\n isValid,\r\n handleChange,\r\n handleBlur,\r\n handleSubmit,\r\n cancelSubmit,\r\n reset,\r\n getFieldProps,\r\n };\r\n}\r\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"nixFormAsync.d.ts","sourceRoot":"","sources":["../../hooks/nixFormAsync.ts"],"names":[],"mappings":"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"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixFormAsync.ts"],
4
- "sourcesContent": ["/* MIT License\r\n\r\n* Copyright (c) 2026 Resty Gonzales\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n* SOFTWARE.\r\n */\r\n// core/hooks/nixFormAsync.js\r\n\r\nimport { nixComputed } from \"./nixComputed.js\";\r\nimport { nixState } from \"./nixState.js\";\r\n\r\ntype ValidationRule<T> = {\r\n required?: boolean;\r\n minLength?: number;\r\n maxLength?: number;\r\n pattern?: RegExp;\r\n custom?: (value: any, values: T) => boolean;\r\n message?: string;\r\n};\r\n\r\ntype ValidationRules<T> = {\r\n [K in keyof T]?: ValidationRule<T>;\r\n};\r\n\r\ntype FormAsyncState<T, D = any, E = any> = {\r\n values: ReturnType<typeof nixState<T>>;\r\n errors: ReturnType<typeof nixState<Partial<Record<keyof T, string>>>>;\r\n touched: ReturnType<typeof nixState<Partial<Record<keyof T, boolean>>>>;\r\n isSubmitting: ReturnType<typeof nixState<boolean>>;\r\n isValid: ReturnType<typeof nixComputed<boolean>>;\r\n data: ReturnType<typeof nixState<D | null>>;\r\n error: ReturnType<typeof nixState<E | null>>;\r\n loading: ReturnType<typeof nixState<boolean>>;\r\n handleChange: (fieldName: keyof T, value: any) => void;\r\n handleBlur: (fieldName: keyof T) => void;\r\n handleSubmit: (\r\n onSubmit: (values: T, signal: AbortSignal) => Promise<D>\r\n ) => void;\r\n cancelSubmit: () => void;\r\n reset: () => void;\r\n getFieldProps: (fieldName: keyof T) => {\r\n value: any;\r\n \"r-input\": (e: any) => void;\r\n \"r-blur\": () => void;\r\n };\r\n};\r\n\r\n/**\r\n * Full-featured reactive form with debounced async API submission.\r\n *\r\n * @param {Object} [initialValues={}] - Initial field values.\r\n * @param {Object} [validationRules={}] - Validation rules for each field.\r\n * @param {Object} [options={}] - Async submit options.\r\n * @param {number} [options.delay=300] - Debounce delay in ms.\r\n * @param {boolean} [options.leading=false] - Invoke submit on leading edge.\r\n * @param {boolean} [options.trailing=true] - Invoke submit on trailing edge.\r\n * @param {number} [options.maxWait] - Maximum wait time before forced invocation.\r\n * @param {boolean} [options.cache=true] - Cache last submission result.\r\n * @returns {Object} Form API with state, validation, and debounced async submission.\r\n */\r\nexport function nixFormAsync<\r\n T extends Record<string, any> = Record<string, any>,\r\n D = any,\r\n E = any,\r\n>(\r\n initialValues: T = {} as T,\r\n validationRules: ValidationRules<T> = {} as ValidationRules<T>,\r\n options: {\r\n delay?: number;\r\n leading?: boolean;\r\n trailing?: boolean;\r\n maxWait?: number;\r\n cache?: boolean;\r\n } = {}\r\n): FormAsyncState<T, D, E> {\r\n const values = nixState<T>({ ...initialValues });\r\n const errors = nixState<Partial<Record<keyof T, string>>>({});\r\n const touched = nixState<Partial<Record<keyof T, boolean>>>({});\r\n const isSubmitting = nixState<boolean>(false);\r\n const isValid = nixComputed<boolean>(\r\n () => Object.keys(errors.value).length === 0\r\n );\r\n\r\n const {\r\n delay = 300,\r\n leading = false,\r\n trailing = true,\r\n maxWait,\r\n cache = true,\r\n } = options;\r\n const data = nixState<D | null>(null);\r\n const error = nixState<E | null>(null);\r\n const loading = nixState<boolean>(false);\r\n\r\n let abortController: AbortController | null = null;\r\n let timerId: ReturnType<typeof setTimeout> | null = null;\r\n let lastInvokeTime = 0;\r\n let lastResult: D | null = null;\r\n let lastError: E | null = null;\r\n let pendingPromise: Promise<D> | null = null;\r\n\r\n function validate(fieldName: keyof T, value: any): string | null {\r\n const rules = validationRules[fieldName];\r\n if (!rules) return null;\r\n\r\n if (rules.required && !value)\r\n return rules.message || `${String(fieldName)} is required`;\r\n if (rules.minLength && value.length < rules.minLength)\r\n return (\r\n rules.message ||\r\n `${String(fieldName)} must be at least ${rules.minLength} characters`\r\n );\r\n if (rules.maxLength && value.length > rules.maxLength)\r\n return (\r\n rules.message ||\r\n `${String(fieldName)} must be at most ${rules.maxLength} characters`\r\n );\r\n if (rules.pattern && !rules.pattern.test(value))\r\n return rules.message || `${String(fieldName)} is invalid`;\r\n if (rules.custom && !rules.custom(value, values.value))\r\n return rules.message || `${String(fieldName)} is invalid`;\r\n\r\n return null;\r\n }\r\n\r\n function handleChange(fieldName: keyof T, value: any): void {\r\n values.value = { ...values.value, [fieldName]: value };\r\n\r\n if (touched.value[fieldName]) {\r\n const err = validate(fieldName, value);\r\n if (err) errors.value = { ...errors.value, [fieldName]: err };\r\n else {\r\n const newErrors = { ...errors.value };\r\n delete newErrors[fieldName];\r\n errors.value = newErrors;\r\n }\r\n }\r\n }\r\n\r\n function handleBlur(fieldName: keyof T): void {\r\n touched.value = { ...touched.value, [fieldName]: true };\r\n const err = validate(fieldName, values.value[fieldName]);\r\n if (err) errors.value = { ...errors.value, [fieldName]: err };\r\n }\r\n\r\n function validateAll(): boolean {\r\n const newErrors: Partial<Record<keyof T, string>> = {};\r\n (Object.keys(validationRules) as Array<keyof T>).forEach((fieldName) => {\r\n const err = validate(fieldName, values.value[fieldName]);\r\n if (err) newErrors[fieldName] = err;\r\n });\r\n errors.value = newErrors;\r\n return Object.keys(newErrors).length === 0;\r\n }\r\n\r\n async function invokeAsync(\r\n onSubmit: (values: T, signal: AbortSignal) => Promise<D>\r\n ): Promise<D | undefined> {\r\n if (cache && lastResult !== null) {\r\n data.value = lastResult;\r\n error.value = lastError;\r\n loading.value = false;\r\n return lastResult;\r\n }\r\n if (abortController) abortController.abort();\r\n abortController = new AbortController();\r\n const signal = abortController.signal;\r\n loading.value = true;\r\n error.value = null;\r\n pendingPromise = onSubmit(values.value, signal);\r\n try {\r\n const result = await pendingPromise;\r\n lastResult = result;\r\n data.value = result;\r\n return result;\r\n } catch (err: any) {\r\n if (err.name !== \"AbortError\") {\r\n lastError = err;\r\n error.value = err;\r\n console.error(\"[nixFormAsync] submit error:\", err);\r\n }\r\n throw err;\r\n } finally {\r\n loading.value = false;\r\n pendingPromise = null;\r\n lastInvokeTime = Date.now();\r\n }\r\n }\r\n\r\n function handleSubmit(\r\n onSubmit: (values: T, signal: AbortSignal) => Promise<D>\r\n ): void {\r\n if (!validateAll()) return;\r\n const now = Date.now();\r\n const timeSinceLastInvoke = now - lastInvokeTime;\r\n const remainingTime = delay - timeSinceLastInvoke;\r\n const shouldInvokeLeading = leading && !timerId;\r\n if (maxWait !== undefined && timeSinceLastInvoke >= maxWait) {\r\n if (timerId) clearTimeout(timerId);\r\n timerId = null;\r\n void invokeAsync(onSubmit);\r\n return;\r\n }\r\n if (timerId) clearTimeout(timerId);\r\n if (shouldInvokeLeading) {\r\n void invokeAsync(onSubmit);\r\n return;\r\n }\r\n if (trailing) {\r\n timerId = setTimeout(\r\n () => {\r\n timerId = null;\r\n void invokeAsync(onSubmit);\r\n },\r\n remainingTime > 0 ? remainingTime : delay\r\n );\r\n }\r\n }\r\n\r\n function cancelSubmit(): void {\r\n if (abortController) {\r\n abortController.abort();\r\n abortController = null;\r\n }\r\n if (timerId) clearTimeout(timerId);\r\n timerId = null;\r\n }\r\n\r\n function reset(): void {\r\n values.value = { ...initialValues };\r\n errors.value = {};\r\n touched.value = {};\r\n isSubmitting.value = false;\r\n cancelSubmit();\r\n data.value = null;\r\n error.value = null;\r\n loading.value = false;\r\n }\r\n\r\n function getFieldProps(fieldName: keyof T) {\r\n return {\r\n value: values.value[fieldName] || \"\",\r\n \"r-input\": (e: any) => handleChange(fieldName, e.target.value),\r\n \"r-blur\": () => handleBlur(fieldName),\r\n };\r\n }\r\n\r\n return {\r\n values,\r\n errors,\r\n touched,\r\n isSubmitting,\r\n isValid,\r\n data,\r\n error,\r\n loading,\r\n handleChange,\r\n handleBlur,\r\n handleSubmit,\r\n cancelSubmit,\r\n reset,\r\n getFieldProps,\r\n };\r\n}\r\n"],
5
- "mappings": ";;AAwBA,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AAmDlB,SAAS,aAKd,gBAAmB,CAAC,GACpB,kBAAsC,CAAC,GACvC,UAMI,CAAC,GACoB;AACzB,QAAM,SAAS,SAAY,EAAE,GAAG,cAAc,CAAC;AAC/C,QAAM,SAAS,SAA2C,CAAC,CAAC;AAC5D,QAAM,UAAU,SAA4C,CAAC,CAAC;AAC9D,QAAM,eAAe,SAAkB,KAAK;AAC5C,QAAM,UAAU;AAAA,IACd,MAAM,OAAO,KAAK,OAAO,KAAK,EAAE,WAAW;AAAA,EAC7C;AAEA,QAAM;AAAA,IACJ,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,WAAW;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,EACV,IAAI;AACJ,QAAM,OAAO,SAAmB,IAAI;AACpC,QAAM,QAAQ,SAAmB,IAAI;AACrC,QAAM,UAAU,SAAkB,KAAK;AAEvC,MAAI,kBAA0C;AAC9C,MAAI,UAAgD;AACpD,MAAI,iBAAiB;AACrB,MAAI,aAAuB;AAC3B,MAAI,YAAsB;AAC1B,MAAI,iBAAoC;AAExC,WAAS,SAAS,WAAoB,OAA2B;AAC/D,UAAM,QAAQ,gBAAgB,SAAS;AACvC,QAAI,CAAC,MAAO,QAAO;AAEnB,QAAI,MAAM,YAAY,CAAC;AACrB,aAAO,MAAM,WAAW,GAAG,OAAO,SAAS,CAAC;AAC9C,QAAI,MAAM,aAAa,MAAM,SAAS,MAAM;AAC1C,aACE,MAAM,WACN,GAAG,OAAO,SAAS,CAAC,qBAAqB,MAAM,SAAS;AAE5D,QAAI,MAAM,aAAa,MAAM,SAAS,MAAM;AAC1C,aACE,MAAM,WACN,GAAG,OAAO,SAAS,CAAC,oBAAoB,MAAM,SAAS;AAE3D,QAAI,MAAM,WAAW,CAAC,MAAM,QAAQ,KAAK,KAAK;AAC5C,aAAO,MAAM,WAAW,GAAG,OAAO,SAAS,CAAC;AAC9C,QAAI,MAAM,UAAU,CAAC,MAAM,OAAO,OAAO,OAAO,KAAK;AACnD,aAAO,MAAM,WAAW,GAAG,OAAO,SAAS,CAAC;AAE9C,WAAO;AAAA,EACT;AAtBS;AAwBT,WAAS,aAAa,WAAoB,OAAkB;AAC1D,WAAO,QAAQ,EAAE,GAAG,OAAO,OAAO,CAAC,SAAS,GAAG,MAAM;AAErD,QAAI,QAAQ,MAAM,SAAS,GAAG;AAC5B,YAAM,MAAM,SAAS,WAAW,KAAK;AACrC,UAAI,IAAK,QAAO,QAAQ,EAAE,GAAG,OAAO,OAAO,CAAC,SAAS,GAAG,IAAI;AAAA,WACvD;AACH,cAAM,YAAY,EAAE,GAAG,OAAO,MAAM;AACpC,eAAO,UAAU,SAAS;AAC1B,eAAO,QAAQ;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAZS;AAcT,WAAS,WAAW,WAA0B;AAC5C,YAAQ,QAAQ,EAAE,GAAG,QAAQ,OAAO,CAAC,SAAS,GAAG,KAAK;AACtD,UAAM,MAAM,SAAS,WAAW,OAAO,MAAM,SAAS,CAAC;AACvD,QAAI,IAAK,QAAO,QAAQ,EAAE,GAAG,OAAO,OAAO,CAAC,SAAS,GAAG,IAAI;AAAA,EAC9D;AAJS;AAMT,WAAS,cAAuB;AAC9B,UAAM,YAA8C,CAAC;AACrD,IAAC,OAAO,KAAK,eAAe,EAAqB,QAAQ,CAAC,cAAc;AACtE,YAAM,MAAM,SAAS,WAAW,OAAO,MAAM,SAAS,CAAC;AACvD,UAAI,IAAK,WAAU,SAAS,IAAI;AAAA,IAClC,CAAC;AACD,WAAO,QAAQ;AACf,WAAO,OAAO,KAAK,SAAS,EAAE,WAAW;AAAA,EAC3C;AARS;AAUT,iBAAe,YACb,UACwB;AACxB,QAAI,SAAS,eAAe,MAAM;AAChC,WAAK,QAAQ;AACb,YAAM,QAAQ;AACd,cAAQ,QAAQ;AAChB,aAAO;AAAA,IACT;AACA,QAAI,gBAAiB,iBAAgB,MAAM;AAC3C,sBAAkB,IAAI,gBAAgB;AACtC,UAAM,SAAS,gBAAgB;AAC/B,YAAQ,QAAQ;AAChB,UAAM,QAAQ;AACd,qBAAiB,SAAS,OAAO,OAAO,MAAM;AAC9C,QAAI;AACF,YAAM,SAAS,MAAM;AACrB,mBAAa;AACb,WAAK,QAAQ;AACb,aAAO;AAAA,IACT,SAAS,KAAU;AACjB,UAAI,IAAI,SAAS,cAAc;AAC7B,oBAAY;AACZ,cAAM,QAAQ;AACd,gBAAQ,MAAM,gCAAgC,GAAG;AAAA,MACnD;AACA,YAAM;AAAA,IACR,UAAE;AACA,cAAQ,QAAQ;AAChB,uBAAiB;AACjB,uBAAiB,KAAK,IAAI;AAAA,IAC5B;AAAA,EACF;AAhCe;AAkCf,WAAS,aACP,UACM;AACN,QAAI,CAAC,YAAY,EAAG;AACpB,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,sBAAsB,MAAM;AAClC,UAAM,gBAAgB,QAAQ;AAC9B,UAAM,sBAAsB,WAAW,CAAC;AACxC,QAAI,YAAY,UAAa,uBAAuB,SAAS;AAC3D,UAAI,QAAS,cAAa,OAAO;AACjC,gBAAU;AACV,WAAK,YAAY,QAAQ;AACzB;AAAA,IACF;AACA,QAAI,QAAS,cAAa,OAAO;AACjC,QAAI,qBAAqB;AACvB,WAAK,YAAY,QAAQ;AACzB;AAAA,IACF;AACA,QAAI,UAAU;AACZ,gBAAU;AAAA,QACR,MAAM;AACJ,oBAAU;AACV,eAAK,YAAY,QAAQ;AAAA,QAC3B;AAAA,QACA,gBAAgB,IAAI,gBAAgB;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AA5BS;AA8BT,WAAS,eAAqB;AAC5B,QAAI,iBAAiB;AACnB,sBAAgB,MAAM;AACtB,wBAAkB;AAAA,IACpB;AACA,QAAI,QAAS,cAAa,OAAO;AACjC,cAAU;AAAA,EACZ;AAPS;AAST,WAAS,QAAc;AACrB,WAAO,QAAQ,EAAE,GAAG,cAAc;AAClC,WAAO,QAAQ,CAAC;AAChB,YAAQ,QAAQ,CAAC;AACjB,iBAAa,QAAQ;AACrB,iBAAa;AACb,SAAK,QAAQ;AACb,UAAM,QAAQ;AACd,YAAQ,QAAQ;AAAA,EAClB;AATS;AAWT,WAAS,cAAc,WAAoB;AACzC,WAAO;AAAA,MACL,OAAO,OAAO,MAAM,SAAS,KAAK;AAAA,MAClC,WAAW,wBAAC,MAAW,aAAa,WAAW,EAAE,OAAO,KAAK,GAAlD;AAAA,MACX,UAAU,6BAAM,WAAW,SAAS,GAA1B;AAAA,IACZ;AAAA,EACF;AANS;AAQT,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AA3MgB;",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"nixInterval.d.ts","sourceRoot":"","sources":["../../hooks/nixInterval.ts"],"names":[],"mappings":"AAgDA,wBAAgB,WAAW,CACzB,EAAE,EAAE,MAAM,IAAI,EACd,EAAE,EAAE,MAAM,EACV,MAAM,CAAC,EAAE,WAAW,GACnB,MAAM,IAAI,CA2BZ"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixInterval.ts"],
4
- "sourcesContent": ["/* MIT License\r\n\r\n* Copyright (c) 2026 Resty Gonzales\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n* SOFTWARE.\r\n */\r\n/**\r\n * @fileoverview Safe interval utility with automatic cleanup support.\r\n * Provides AbortController integration for cancellable intervals.\r\n */\r\n\r\n/**\r\n * Safe interval with automatic cleanup support and optional AbortController.\r\n * Must be called within a component and cleaned up on unmount.\r\n *\r\n * @param {() => void} fn - Function to run at each interval\r\n * @param {number} ms - Interval duration in milliseconds\r\n * @param {AbortSignal} [signal] - Optional AbortSignal to cancel the interval\r\n * @returns {() => void} Cleanup function to stop the interval\r\n *\r\n * @example\r\n * const cancel = nixInterval(() => console.log('tick'), 1000);\r\n * // stop interval\r\n * cancel();\r\n *\r\n * @example\r\n * const controller = new AbortController();\r\n * nixInterval(() => console.log('tick'), 1000, controller.signal);\r\n * controller.abort(); // automatically clears interval\r\n *\r\n * @throws {TypeError} If fn is not a function or ms is not a non-negative number\r\n */\r\nexport function nixInterval(\r\n fn: () => void,\r\n ms: number,\r\n signal?: AbortSignal\r\n): () => void {\r\n if (typeof fn !== \"function\") {\r\n throw new TypeError(\"nixInterval: first argument must be a function\");\r\n }\r\n if (typeof ms !== \"number\" || ms < 0) {\r\n throw new TypeError(\r\n \"nixInterval: second argument must be a non-negative number\"\r\n );\r\n }\r\n\r\n const id = setInterval(fn, ms);\r\n\r\n const cancel = () => clearInterval(id);\r\n\r\n if (signal) {\r\n if (signal.aborted) {\r\n cancel();\r\n } else {\r\n const listener = () => {\r\n cancel();\r\n signal.removeEventListener(\"abort\", listener);\r\n };\r\n signal.addEventListener(\"abort\", listener);\r\n }\r\n }\r\n\r\n return cancel;\r\n}\r\n"],
5
- "mappings": ";;AAgDO,SAAS,YACd,IACA,IACA,QACY;AACZ,MAAI,OAAO,OAAO,YAAY;AAC5B,UAAM,IAAI,UAAU,gDAAgD;AAAA,EACtE;AACA,MAAI,OAAO,OAAO,YAAY,KAAK,GAAG;AACpC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,KAAK,YAAY,IAAI,EAAE;AAE7B,QAAM,SAAS,6BAAM,cAAc,EAAE,GAAtB;AAEf,MAAI,QAAQ;AACV,QAAI,OAAO,SAAS;AAClB,aAAO;AAAA,IACT,OAAO;AACL,YAAM,WAAW,6BAAM;AACrB,eAAO;AACP,eAAO,oBAAoB,SAAS,QAAQ;AAAA,MAC9C,GAHiB;AAIjB,aAAO,iBAAiB,SAAS,QAAQ;AAAA,IAC3C;AAAA,EACF;AAEA,SAAO;AACT;AA/BgB;",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"nixLazy.d.ts","sourceRoot":"","sources":["../../hooks/nixLazy.ts"],"names":[],"mappings":"AAgCA,wBAAgB,OAAO,CAAC,MAAM,GAAG,GAAG,EAClC,QAAQ,EAAE,MAAM,OAAO,CACrB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAA;CAAE,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAC,CAChE,GACA,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CA4CxB;AAUD,wBAAgB,QAAQ,CAAC,CAAC,GAAG,GAAG,EAAE,EAChC,QAAQ,EACR,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,GAAG,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC,CAAC;CACnB,GAAG,CAAC,GAAG,GAAG,CAqBV"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixLazy.ts"],
4
- "sourcesContent": ["/* MIT License\r\n\r\n* Copyright (c) 2026 Resty Gonzales\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n* SOFTWARE.\r\n */\r\n// core/hooks/nixLazy.js\r\nimport { activeContext } from \"../context/context.js\";\r\nimport { nixState } from \"./nixState.js\";\r\n\r\n/**\r\n * Lazy-load a module/component with caching.\r\n *\r\n * @param {() => Promise<any>} importFn - Function that returns a dynamic import.\r\n * @returns {Function} Component wrapper for lazy-loaded module.\r\n */\r\nexport function nixLazy<TProps = any>(\r\n importFn: () => Promise<\r\n { default?: (props: TProps) => any } | ((props: TProps) => any)\r\n >\r\n): (props: TProps) => any {\r\n type Cache = {\r\n status: \"pending\" | \"success\" | \"error\";\r\n component: ((props: TProps) => any) | null;\r\n error: any;\r\n promise: Promise<any> | null;\r\n };\r\n const cache: Cache = {\r\n status: \"pending\",\r\n component: null,\r\n error: null,\r\n promise: null,\r\n };\r\n\r\n let canceled = false;\r\n\r\n cache.promise = importFn()\r\n .then((module) => {\r\n if (!canceled) {\r\n cache.status = \"success\";\r\n cache.component = (module as any).default || module;\r\n }\r\n })\r\n .catch((err) => {\r\n if (!canceled) {\r\n cache.status = \"error\";\r\n cache.error = err;\r\n }\r\n });\r\n\r\n return function LazyWrapper(props: TProps): any {\r\n const ctx = activeContext;\r\n if (!ctx) throw new Error(\"nixLazy() called outside component\");\r\n\r\n if (cache.status === \"pending\") {\r\n throw cache.promise; // Suspense-like behavior\r\n }\r\n\r\n if (cache.status === \"error\") {\r\n throw cache.error;\r\n }\r\n\r\n return cache.component!(props);\r\n };\r\n}\r\n\r\n/**\r\n * Suspense-like wrapper for lazy components.\r\n *\r\n * @param {Object} props\r\n * @param {any} props.fallback - Element to render while loading.\r\n * @param {Function} props.children - Function returning child component.\r\n * @returns {any} Rendered fallback or child.\r\n */\r\nexport function Suspense<T = any>({\r\n fallback,\r\n children,\r\n}: {\r\n fallback: any;\r\n children: () => T;\r\n}): T | any {\r\n const loading = nixState<boolean>(false);\r\n const error = nixState<any>(null);\r\n\r\n try {\r\n return children();\r\n } catch (promise) {\r\n if (promise instanceof Promise) {\r\n loading.value = true;\r\n promise\r\n .then(() => {\r\n loading.value = false;\r\n })\r\n .catch((err) => {\r\n error.value = err;\r\n loading.value = false;\r\n });\r\n return fallback;\r\n }\r\n throw promise;\r\n }\r\n}\r\n"],
5
- "mappings": ";;AAuBA,SAAS,qBAAqB;AAC9B,SAAS,gBAAgB;AAQlB,SAAS,QACd,UAGwB;AAOxB,QAAM,QAAe;AAAA,IACnB,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,OAAO;AAAA,IACP,SAAS;AAAA,EACX;AAEA,MAAI,WAAW;AAEf,QAAM,UAAU,SAAS,EACtB,KAAK,CAAC,WAAW;AAChB,QAAI,CAAC,UAAU;AACb,YAAM,SAAS;AACf,YAAM,YAAa,OAAe,WAAW;AAAA,IAC/C;AAAA,EACF,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,QAAI,CAAC,UAAU;AACb,YAAM,SAAS;AACf,YAAM,QAAQ;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,SAAO,gCAAS,YAAY,OAAoB;AAC9C,UAAM,MAAM;AACZ,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,oCAAoC;AAE9D,QAAI,MAAM,WAAW,WAAW;AAC9B,YAAM,MAAM;AAAA,IACd;AAEA,QAAI,MAAM,WAAW,SAAS;AAC5B,YAAM,MAAM;AAAA,IACd;AAEA,WAAO,MAAM,UAAW,KAAK;AAAA,EAC/B,GAbO;AAcT;AAhDgB;AA0DT,SAAS,SAAkB;AAAA,EAChC;AAAA,EACA;AACF,GAGY;AACV,QAAM,UAAU,SAAkB,KAAK;AACvC,QAAM,QAAQ,SAAc,IAAI;AAEhC,MAAI;AACF,WAAO,SAAS;AAAA,EAClB,SAAS,SAAS;AAChB,QAAI,mBAAmB,SAAS;AAC9B,cAAQ,QAAQ;AAChB,cACG,KAAK,MAAM;AACV,gBAAQ,QAAQ;AAAA,MAClB,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,cAAM,QAAQ;AACd,gBAAQ,QAAQ;AAAA,MAClB,CAAC;AACH,aAAO;AAAA,IACT;AACA,UAAM;AAAA,EACR;AACF;AA3BgB;",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"nixLazyAsync.d.ts","sourceRoot":"","sources":["../../hooks/nixLazyAsync.ts"],"names":[],"mappings":"AAqCA,wBAAgB,YAAY,CAAC,MAAM,GAAG,GAAG,EACvC,QAAQ,EAAE,MAAM,OAAO,CACrB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAA;CAAE,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAC,CAChE,EACD,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAgExB;AAUD,wBAAgB,QAAQ,CAAC,CAAC,GAAG,GAAG,EAAE,EAChC,QAAQ,EACR,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,GAAG,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC,CAAC;CACnB,GAAG,CAAC,GAAG,GAAG,CAmBV"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixLazyAsync.ts"],
4
- "sourcesContent": ["/* MIT License\r\n\r\n* Copyright (c) 2026 Resty Gonzales\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n* SOFTWARE.\r\n */\r\n// core/hooks/nixLazyAsync.js\r\nimport { activeContext } from \"../context/context.js\";\r\nimport { nixState } from \"./nixState.js\";\r\n\r\n/**\r\n * Lazy-load a module/component with caching, retry, and abort support.\r\n *\r\n * @param {() => Promise<any>} importFn - Function returning a dynamic import.\r\n * @param {Object} [options={}] - Options for lazy loading.\r\n * @param {number} [options.retry=0] - Number of retry attempts on failure.\r\n * @returns {Function} Component wrapper for lazy-loaded module.\r\n *\r\n * @example\r\n * const LazyComp = nixLazyAsync(() => import(\"./MyComponent\"), { retry: 2 });\r\n */\r\nexport function nixLazyAsync<TProps = any>(\r\n importFn: () => Promise<\r\n { default?: (props: TProps) => any } | ((props: TProps) => any)\r\n >,\r\n options: { retry?: number } = {}\r\n): (props: TProps) => any {\r\n const { retry = 0 } = options;\r\n\r\n type Cache = {\r\n status: \"pending\" | \"success\" | \"error\";\r\n component: ((props: TProps) => any) | null;\r\n error: any;\r\n promise: Promise<any> | null;\r\n retriesLeft: number;\r\n };\r\n const cache: Cache = {\r\n status: \"pending\",\r\n component: null,\r\n error: null,\r\n promise: null,\r\n retriesLeft: retry,\r\n };\r\n\r\n let canceled = false;\r\n\r\n const loadModule = (): Promise<any> => {\r\n cache.promise = importFn()\r\n .then((module) => {\r\n if (!canceled) {\r\n cache.status = \"success\";\r\n cache.component = (module as any).default || module;\r\n }\r\n return cache.component;\r\n })\r\n .catch((err) => {\r\n if (!canceled) {\r\n if (cache.retriesLeft > 0) {\r\n cache.retriesLeft--;\r\n return loadModule();\r\n }\r\n cache.status = \"error\";\r\n cache.error = err;\r\n }\r\n return Promise.reject(cache.error);\r\n });\r\n return cache.promise;\r\n };\r\n\r\n loadModule();\r\n\r\n // Removed unused 'cancel' function\r\n\r\n return function LazyWrapper(props: TProps): any {\r\n const ctx = activeContext;\r\n if (!ctx) throw new Error(\"nixLazyAsync() called outside component\");\r\n\r\n if (cache.status === \"pending\") {\r\n throw cache.promise; // Suspense fallback\r\n }\r\n\r\n if (cache.status === \"error\") {\r\n throw cache.error;\r\n }\r\n\r\n if (!cache.component) {\r\n throw new Error(\"nixLazyAsync: component not loaded\");\r\n }\r\n return cache.component(props);\r\n };\r\n}\r\n\r\n/**\r\n * Suspense wrapper to catch pending promises and render fallback.\r\n *\r\n * @param {Object} props\r\n * @param {any} props.fallback - Element to render while loading.\r\n * @param {Function} props.children - Function returning child component.\r\n * @returns {any} Rendered fallback or child component.\r\n */\r\nexport function Suspense<T = any>({\r\n fallback,\r\n children,\r\n}: {\r\n fallback: any;\r\n children: () => T;\r\n}): T | any {\r\n const loading = nixState<boolean>(false);\r\n const error = nixState<any>(null);\r\n\r\n try {\r\n return children();\r\n } catch (promise) {\r\n if (promise instanceof Promise) {\r\n loading.value = true;\r\n promise\r\n .then(() => (loading.value = false))\r\n .catch((err) => {\r\n error.value = err;\r\n loading.value = false;\r\n });\r\n return fallback;\r\n }\r\n throw promise;\r\n }\r\n}\r\n"],
5
- "mappings": ";;AAuBA,SAAS,qBAAqB;AAC9B,SAAS,gBAAgB;AAalB,SAAS,aACd,UAGA,UAA8B,CAAC,GACP;AACxB,QAAM,EAAE,QAAQ,EAAE,IAAI;AAStB,QAAM,QAAe;AAAA,IACnB,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,OAAO;AAAA,IACP,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAEA,MAAI,WAAW;AAEf,QAAM,aAAa,6BAAoB;AACrC,UAAM,UAAU,SAAS,EACtB,KAAK,CAAC,WAAW;AAChB,UAAI,CAAC,UAAU;AACb,cAAM,SAAS;AACf,cAAM,YAAa,OAAe,WAAW;AAAA,MAC/C;AACA,aAAO,MAAM;AAAA,IACf,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,UAAI,CAAC,UAAU;AACb,YAAI,MAAM,cAAc,GAAG;AACzB,gBAAM;AACN,iBAAO,WAAW;AAAA,QACpB;AACA,cAAM,SAAS;AACf,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO,QAAQ,OAAO,MAAM,KAAK;AAAA,IACnC,CAAC;AACH,WAAO,MAAM;AAAA,EACf,GArBmB;AAuBnB,aAAW;AAIX,SAAO,gCAAS,YAAY,OAAoB;AAC9C,UAAM,MAAM;AACZ,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,yCAAyC;AAEnE,QAAI,MAAM,WAAW,WAAW;AAC9B,YAAM,MAAM;AAAA,IACd;AAEA,QAAI,MAAM,WAAW,SAAS;AAC5B,YAAM,MAAM;AAAA,IACd;AAEA,QAAI,CAAC,MAAM,WAAW;AACpB,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AACA,WAAO,MAAM,UAAU,KAAK;AAAA,EAC9B,GAhBO;AAiBT;AArEgB;AA+ET,SAAS,SAAkB;AAAA,EAChC;AAAA,EACA;AACF,GAGY;AACV,QAAM,UAAU,SAAkB,KAAK;AACvC,QAAM,QAAQ,SAAc,IAAI;AAEhC,MAAI;AACF,WAAO,SAAS;AAAA,EAClB,SAAS,SAAS;AAChB,QAAI,mBAAmB,SAAS;AAC9B,cAAQ,QAAQ;AAChB,cACG,KAAK,MAAO,QAAQ,QAAQ,KAAM,EAClC,MAAM,CAAC,QAAQ;AACd,cAAM,QAAQ;AACd,gBAAQ,QAAQ;AAAA,MAClB,CAAC;AACH,aAAO;AAAA,IACT;AACA,UAAM;AAAA,EACR;AACF;AAzBgB;",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"nixLazyFormAsync.d.ts","sourceRoot":"","sources":["../../hooks/nixLazyFormAsync.ts"],"names":[],"mappings":"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"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixLazyFormAsync.ts"],
4
- "sourcesContent": ["/* MIT License\r\n\r\n* Copyright (c) 2026 Resty Gonzales\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n* SOFTWARE.\r\n */\r\n// core/hooks/nixLazyFormAsync.js\r\nimport { activeContext } from \"../context/context.js\";\r\nimport { nixComputed } from \"./nixComputed.js\";\r\nimport { nixState } from \"./nixState.js\";\r\n\r\n/**\r\n * Lazy-load a form component and manage its state with debounced async submissions.\r\n *\r\n * @param {() => Promise<any>} importFn - Function returning a dynamic import of the form component.\r\n * @param {Object} [formOptions={}] - Initial values and validation rules.\r\n * @param {Object} [formOptions.initialValues={}] - Initial field values.\r\n * @param {Object} [formOptions.validationRules={}] - Validation rules per field.\r\n * @param {Object} [submitOptions={}] - Debounce and async submission options.\r\n * @param {number} [submitOptions.delay=300] - Debounce delay.\r\n * @param {boolean} [submitOptions.leading=false] - Invoke submit on leading edge.\r\n * @param {boolean} [submitOptions.trailing=true] - Invoke submit on trailing edge.\r\n * @param {number} [submitOptions.maxWait] - Max wait before forced submission.\r\n * @param {boolean} [submitOptions.cache=true] - Cache last submission result.\r\n * @param {Object} [lazyOptions={}] - Options for lazy-loaded component import.\r\n * @param {number} [lazyOptions.retry=0] - Retry count for lazy-loaded component import.\r\n * @returns {Object} Lazy-loaded form component and reactive form API.\r\n */\r\ntype ValidationRule<T> = {\r\n required?: boolean;\r\n minLength?: number;\r\n maxLength?: number;\r\n pattern?: RegExp;\r\n custom?: (value: any, values: T) => boolean;\r\n message?: string;\r\n};\r\n\r\ntype ValidationRules<T> = {\r\n [K in keyof T]?: ValidationRule<T>;\r\n};\r\n\r\ntype LazyFormAsyncReturn<T, D = any, E = any, P = any> = {\r\n LazyComponentWrapper: (props: P) => any;\r\n values: ReturnType<typeof nixState<T>>;\r\n errors: ReturnType<typeof nixState<Partial<Record<keyof T, string>>>>;\r\n touched: ReturnType<typeof nixState<Partial<Record<keyof T, boolean>>>>;\r\n isSubmitting: ReturnType<typeof nixState<boolean>>;\r\n isValid: ReturnType<typeof nixComputed<boolean>>;\r\n data: ReturnType<typeof nixState<D | null>>;\r\n error: ReturnType<typeof nixState<E | null>>;\r\n loading: ReturnType<typeof nixState<boolean>>;\r\n handleChange: (fieldName: keyof T, value: any) => void;\r\n handleBlur: (fieldName: keyof T) => void;\r\n handleSubmit: (\r\n onSubmit: (values: T, signal: AbortSignal) => Promise<D>\r\n ) => void;\r\n cancelSubmit: () => void;\r\n reset: () => void;\r\n getFieldProps: (fieldName: keyof T) => {\r\n value: any;\r\n \"r-input\": (e: any) => void;\r\n \"r-blur\": () => void;\r\n };\r\n};\r\n\r\nexport function nixLazyFormAsync<\r\n T extends Record<string, any> = Record<string, any>,\r\n D = any,\r\n E = any,\r\n P = any,\r\n>(\r\n importFn: () => Promise<\r\n { default?: (props: P) => any } | ((props: P) => any)\r\n >,\r\n formOptions: { initialValues?: T; validationRules?: ValidationRules<T> } = {},\r\n submitOptions: {\r\n delay?: number;\r\n leading?: boolean;\r\n trailing?: boolean;\r\n maxWait?: number;\r\n cache?: boolean;\r\n } = {},\r\n lazyOptions: { retry?: number } = {}\r\n): LazyFormAsyncReturn<T, D, E, P> {\r\n const {\r\n initialValues = {} as T,\r\n validationRules = {} as ValidationRules<T>,\r\n } = formOptions;\r\n const { retry = 0 } = lazyOptions;\r\n const {\r\n delay = 300,\r\n leading = false,\r\n trailing = true,\r\n maxWait,\r\n cache = true,\r\n } = submitOptions;\r\n\r\n type LazyCache = {\r\n status: \"pending\" | \"success\" | \"error\";\r\n component: ((props: P) => any) | null;\r\n error: any;\r\n promise: Promise<any> | null;\r\n retriesLeft: number;\r\n };\r\n const lazyCache: LazyCache = {\r\n status: \"pending\",\r\n component: null,\r\n error: null,\r\n promise: null,\r\n retriesLeft: retry,\r\n };\r\n\r\n let lazyAbortController: AbortController | null = new AbortController();\r\n let lazyCanceled = false;\r\n\r\n const loadLazy = (): Promise<any> => {\r\n lazyCache.promise = importFn()\r\n .then((module) => {\r\n if (!lazyCanceled) {\r\n lazyCache.status = \"success\";\r\n lazyCache.component = (module as any).default || module;\r\n }\r\n })\r\n .catch((err) => {\r\n if (!lazyCanceled) {\r\n if (lazyCache.retriesLeft > 0) {\r\n lazyCache.retriesLeft--;\r\n return loadLazy();\r\n }\r\n lazyCache.status = \"error\";\r\n lazyCache.error = err;\r\n }\r\n return Promise.reject(err);\r\n });\r\n return lazyCache.promise;\r\n };\r\n\r\n loadLazy();\r\n\r\n const cancelLazyLoad = (): void => {\r\n lazyCanceled = true;\r\n if (lazyAbortController) {\r\n lazyAbortController.abort();\r\n lazyAbortController = null;\r\n }\r\n };\r\n\r\n const LazyComponentWrapper = (props: P): any => {\r\n const ctx = activeContext;\r\n if (!ctx) throw new Error(\"nixLazyFormAsync: called outside component\");\r\n if (lazyCache.status === \"pending\") throw lazyCache.promise;\r\n if (lazyCache.status === \"error\") throw lazyCache.error;\r\n return lazyCache.component!(props);\r\n };\r\n\r\n /** ---------------- Form State ---------------- */\r\n const values = nixState({ ...initialValues });\r\n const errors = nixState<Partial<Record<keyof T, string>>>({});\r\n const touched = nixState<Partial<Record<keyof T, boolean>>>({});\r\n const isSubmitting = nixState(false);\r\n const isValid = nixComputed(() => Object.keys(errors.value).length === 0);\r\n\r\n /** Async submit state */\r\n const data = nixState<D | null>(null);\r\n const error = nixState<E | null>(null);\r\n const loading = nixState(false);\r\n\r\n let abortController: AbortController | null = null;\r\n let timerId: ReturnType<typeof setTimeout> | null = null;\r\n let lastInvokeTime = 0;\r\n let lastResult: D | null = null;\r\n let lastError: E | null = null;\r\n let pendingPromise: Promise<D> | null = null;\r\n\r\n /** ---------------- Form Validation ---------------- */\r\n\r\n function validate(fieldName: keyof T, value: any): string | null {\r\n const rules = validationRules[fieldName];\r\n if (!rules) return null;\r\n\r\n if (rules.required && !value)\r\n return rules.message || `${String(fieldName)} is required`;\r\n if (rules.minLength && value.length < rules.minLength)\r\n return (\r\n rules.message ||\r\n `${String(fieldName)} must be at least ${rules.minLength} characters`\r\n );\r\n if (rules.maxLength && value.length > rules.maxLength)\r\n return (\r\n rules.message ||\r\n `${String(fieldName)} must be at most ${rules.maxLength} characters`\r\n );\r\n if (rules.pattern && !rules.pattern.test(value))\r\n return rules.message || `${String(fieldName)} is invalid`;\r\n if (rules.custom && !rules.custom(value, values.value))\r\n return rules.message || `${String(fieldName)} is invalid`;\r\n\r\n return null;\r\n }\r\n\r\n function handleChange(fieldName: keyof T, value: any): void {\r\n values.value = { ...values.value, [fieldName]: value };\r\n\r\n if ((touched.value as Partial<Record<keyof T, boolean>>)[fieldName]) {\r\n const err = validate(fieldName, value);\r\n if (err) errors.value = { ...errors.value, [fieldName]: err };\r\n else {\r\n const newErrors = { ...errors.value };\r\n delete newErrors[fieldName];\r\n errors.value = newErrors;\r\n }\r\n }\r\n }\r\n\r\n function handleBlur(fieldName: keyof T): void {\r\n touched.value = { ...touched.value, [fieldName]: true };\r\n const err = validate(fieldName, values.value[fieldName]);\r\n if (err) errors.value = { ...errors.value, [fieldName]: err };\r\n }\r\n\r\n function validateAll(): boolean {\r\n const newErrors: Partial<Record<keyof T, string>> = {};\r\n (Object.keys(validationRules) as Array<keyof T>).forEach((fieldName) => {\r\n const err = validate(fieldName, values.value[fieldName]);\r\n if (err) newErrors[fieldName] = err;\r\n });\r\n errors.value = newErrors;\r\n return Object.keys(newErrors).length === 0;\r\n }\r\n\r\n /** ---------------- Debounced Async Submit ---------------- */\r\n\r\n async function invokeAsync(\r\n onSubmit: (values: T, signal: AbortSignal) => Promise<D>\r\n ): Promise<D | undefined> {\r\n // Use cache if enabled and lastResult exists\r\n if (cache && lastResult !== null) {\r\n data.value = lastResult ?? null;\r\n error.value = lastError ?? null;\r\n loading.value = false;\r\n return lastResult;\r\n }\r\n\r\n if (abortController) abortController.abort();\r\n abortController = new AbortController();\r\n const signal = abortController.signal;\r\n\r\n loading.value = true;\r\n error.value = null;\r\n\r\n pendingPromise = onSubmit(values.value, signal);\r\n\r\n try {\r\n const result = await pendingPromise;\r\n lastResult = result;\r\n data.value = result ?? null;\r\n return result;\r\n } catch (err: any) {\r\n if (err.name !== \"AbortError\") {\r\n lastError = err;\r\n error.value = err;\r\n }\r\n throw err;\r\n } finally {\r\n loading.value = false;\r\n pendingPromise = null;\r\n lastInvokeTime = Date.now();\r\n }\r\n }\r\n\r\n function handleSubmit(\r\n onSubmit: (values: T, signal: AbortSignal) => Promise<D>\r\n ): void {\r\n if (!validateAll()) return;\r\n\r\n const now = Date.now();\r\n const timeSinceLastInvoke = now - lastInvokeTime;\r\n const remainingTime = delay - timeSinceLastInvoke;\r\n const shouldInvokeLeading = leading && !timerId;\r\n\r\n if (maxWait !== undefined && timeSinceLastInvoke >= maxWait) {\r\n if (timerId) clearTimeout(timerId);\r\n timerId = null;\r\n void invokeAsync(onSubmit);\r\n return;\r\n }\r\n\r\n if (timerId) clearTimeout(timerId);\r\n\r\n if (shouldInvokeLeading) {\r\n void invokeAsync(onSubmit);\r\n return;\r\n }\r\n\r\n if (trailing) {\r\n timerId = setTimeout(\r\n () => {\r\n timerId = null;\r\n void invokeAsync(onSubmit);\r\n },\r\n remainingTime > 0 ? remainingTime : delay\r\n );\r\n }\r\n }\r\n\r\n /** Cancel pending submit */\r\n\r\n function cancelSubmit(): void {\r\n if (abortController) {\r\n abortController.abort();\r\n abortController = null;\r\n }\r\n if (timerId) clearTimeout(timerId);\r\n timerId = null;\r\n }\r\n\r\n function reset(): void {\r\n values.value = { ...initialValues };\r\n errors.value = {};\r\n touched.value = {};\r\n isSubmitting.value = false;\r\n cancelSubmit();\r\n cancelLazyLoad();\r\n data.value = null;\r\n error.value = null;\r\n loading.value = false;\r\n }\r\n\r\n function getFieldProps(fieldName: keyof T) {\r\n return {\r\n value: values.value[fieldName] || \"\",\r\n \"r-input\": (e: any) => handleChange(fieldName, e.target.value),\r\n \"r-blur\": () => handleBlur(fieldName),\r\n };\r\n }\r\n\r\n return {\r\n LazyComponentWrapper,\r\n values,\r\n errors,\r\n touched,\r\n isSubmitting,\r\n isValid,\r\n data,\r\n error,\r\n loading,\r\n handleChange,\r\n handleBlur,\r\n handleSubmit,\r\n cancelSubmit,\r\n reset,\r\n getFieldProps,\r\n };\r\n}\r\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"nixLocalStorage.d.ts","sourceRoot":"","sources":["../../hooks/nixLocalStorage.ts"],"names":[],"mappings":"AAiIA,wBAAgB,eAAe,CAAC,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,CAAC,GACT;IACD,KAAK,EAAE,CAAC,CAAC;IACT,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;IACvB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,OAAO,CAAC;CACxB,CA8FA"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixLocalStorage.ts"],
4
- "sourcesContent": ["/* MIT License\r\n\r\n* Copyright (c) 2026 Resty Gonzales\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n* SOFTWARE.\r\n */\r\n/**\r\n * @fileoverview Reactive localStorage hook for Fynix.\r\n * Automatically syncs state with localStorage using JSON serialization.\r\n */\r\n\r\nimport { nixState } from \"./nixState\";\r\n\r\n/**\r\n * Safe JSON parsing with validation to prevent code injection\r\n * @param value - String to parse\r\n * @param fallback - Fallback value if parsing fails\r\n * @returns Parsed value or fallback\r\n */\r\nfunction safeJSONParse<T>(value: string | null, fallback: T): T {\r\n if (value === null || value === undefined) {\r\n return fallback;\r\n }\r\n\r\n try {\r\n // Basic validation: check for suspicious patterns\r\n if (typeof value !== \"string\") {\r\n console.warn(\"[nixLocalStorage] Non-string value provided to JSON.parse\");\r\n return fallback;\r\n }\r\n\r\n // Check for potentially malicious patterns\r\n const suspiciousPatterns = [\r\n /__proto__/,\r\n /constructor/,\r\n /prototype/,\r\n /function\\s*\\(/,\r\n /=>\\s*{/,\r\n /javascript:/,\r\n /<script/i,\r\n ];\r\n\r\n for (const pattern of suspiciousPatterns) {\r\n if (pattern.test(value)) {\r\n console.warn(\r\n \"[nixLocalStorage] Potentially malicious content detected, using fallback\"\r\n );\r\n return fallback;\r\n }\r\n }\r\n\r\n // Parse and validate the result\r\n const parsed = JSON.parse(value);\r\n\r\n // Additional validation: ensure the parsed object doesn't have dangerous properties\r\n if (parsed && typeof parsed === \"object\") {\r\n if (parsed.constructor !== Object && parsed.constructor !== Array) {\r\n console.warn(\"[nixLocalStorage] Unsafe object constructor detected\");\r\n return fallback;\r\n }\r\n }\r\n\r\n return parsed as T;\r\n } catch (error) {\r\n console.warn(\"[nixLocalStorage] JSON parsing failed:\", error);\r\n return fallback;\r\n }\r\n}\r\n\r\n/**\r\n * Safe JSON stringification with size limits\r\n * @param value - Value to stringify\r\n * @param maxSize - Maximum size in characters (default: 1MB)\r\n * @returns JSON string or null if too large/invalid\r\n */\r\nfunction safeJSONStringify<T>(value: T, maxSize = 1024 * 1024): string | null {\r\n try {\r\n const stringified = JSON.stringify(value);\r\n\r\n if (stringified.length > maxSize) {\r\n console.warn(\r\n \"[nixLocalStorage] Value too large to store:\",\r\n stringified.length,\r\n \"characters\"\r\n );\r\n return null;\r\n }\r\n\r\n return stringified;\r\n } catch (error) {\r\n console.warn(\"[nixLocalStorage] JSON stringification failed:\", error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Reactive wrapper around localStorage with safe JSON parsing/stringifying.\r\n * Automatically persists state changes to localStorage.\r\n *\r\n * @template T\r\n * @param {string} key - LocalStorage key\r\n * @param {T} initial - Initial value if key does not exist\r\n * @returns {{ value: T, set: (v: T) => void, clear: () => void, getSize: () => number }} Secure storage object\r\n *\r\n * @example\r\n * const theme = nixLocalStorage('theme', 'light');\r\n * console.log(theme.value); // 'light' or stored value\r\n * theme.set('dark'); // Updates state and localStorage\r\n *\r\n * @example\r\n * const user = nixLocalStorage('user', { name: '', age: 0 });\r\n * user.set({ name: 'John', age: 30 });\r\n */\r\nexport function nixLocalStorage<T>(\r\n key: string,\r\n initial: T\r\n): {\r\n value: T;\r\n set: (v: T) => boolean;\r\n clear: () => void;\r\n getSize: () => number;\r\n isValid: () => boolean;\r\n} {\r\n // Validate inputs\r\n if (!key || typeof key !== \"string\") {\r\n throw new Error(\"[nixLocalStorage] Key must be a non-empty string\");\r\n }\r\n\r\n if (key.length > 100) {\r\n throw new Error(\"[nixLocalStorage] Key too long (max 100 characters)\");\r\n }\r\n\r\n let initialValue: T;\r\n let isStorageValid = true;\r\n\r\n try {\r\n // Check if localStorage is available\r\n if (typeof localStorage === \"undefined\") {\r\n console.warn(\r\n \"[nixLocalStorage] localStorage not available, using in-memory fallback\"\r\n );\r\n isStorageValid = false;\r\n initialValue = initial;\r\n } else {\r\n const stored = localStorage.getItem(key);\r\n initialValue = safeJSONParse(stored, initial);\r\n }\r\n } catch (err) {\r\n console.error(`[nixLocalStorage] Error reading key \"${key}\":`, err);\r\n initialValue = initial;\r\n isStorageValid = false;\r\n }\r\n\r\n const state = nixState<T>(initialValue);\r\n\r\n const set = (v: T): boolean => {\r\n if (!isStorageValid) {\r\n state.value = v;\r\n return false;\r\n }\r\n\r\n try {\r\n const stringified = safeJSONStringify(v);\r\n if (stringified === null) {\r\n console.error(\r\n `[nixLocalStorage] Failed to stringify value for key \"${key}\"`\r\n );\r\n return false;\r\n }\r\n\r\n localStorage.setItem(key, stringified);\r\n state.value = v;\r\n return true;\r\n } catch (err) {\r\n console.error(`[nixLocalStorage] Error setting key \"${key}\":`, err);\r\n // Update state even if localStorage fails (in-memory fallback)\r\n state.value = v;\r\n return false;\r\n }\r\n };\r\n\r\n const clear = (): void => {\r\n try {\r\n if (isStorageValid) {\r\n localStorage.removeItem(key);\r\n }\r\n state.value = initial;\r\n } catch (err) {\r\n console.error(`[nixLocalStorage] Error clearing key \"${key}\":`, err);\r\n }\r\n };\r\n\r\n const getSize = (): number => {\r\n try {\r\n if (!isStorageValid) return 0;\r\n const stored = localStorage.getItem(key);\r\n return stored ? stored.length : 0;\r\n } catch {\r\n return 0;\r\n }\r\n };\r\n\r\n const isValid = (): boolean => isStorageValid;\r\n\r\n return {\r\n get value() {\r\n return state.value;\r\n },\r\n set value(v: T) {\r\n set(v);\r\n },\r\n set,\r\n clear,\r\n getSize,\r\n isValid,\r\n };\r\n}\r\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"nixMemo.d.ts","sourceRoot":"","sources":["../../hooks/nixMemo.ts"],"names":[],"mappings":"AA+BA,wBAAgB,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,IAAI,GAAE,GAAG,EAAO,GAAG,CAAC,GAAG,SAAS,CAuC5E"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixMemo.ts"],
4
- "sourcesContent": ["/* MIT License\r\n\r\n* Copyright (c) 2026 Resty Gonzales\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n* SOFTWARE.\r\n */\r\nimport { activeContext } from \"../context/context\";\r\n\r\n/**\r\n * Memoize a value based on dependencies, similar to React's useMemo.\r\n *\r\n * @param {() => any} factory - Function to compute the memoized value\r\n * @param {Array<any>} deps - Dependency array\r\n * @returns {any} Memoized value\r\n */\r\nexport function nixMemo<T>(factory: () => T, deps: any[] = []): T | undefined {\r\n type MemoHook = { value: T; deps: any[] };\r\n const ctx = activeContext as\r\n | (typeof activeContext & {\r\n hookIndex: number;\r\n hooks: Array<MemoHook | undefined>;\r\n })\r\n | undefined;\r\n if (!ctx) throw new Error(\"nixMemo() called outside component\");\r\n\r\n if (typeof factory !== \"function\") {\r\n console.error(\"[nixMemo] First argument must be a function\");\r\n return undefined;\r\n }\r\n\r\n if (!Array.isArray(deps)) {\r\n console.error(\"[nixMemo] Second argument must be an array\");\r\n deps = [];\r\n }\r\n\r\n const idx: number = ctx.hookIndex++;\r\n const prev = ctx.hooks[idx] as MemoHook | undefined;\r\n\r\n const hasChanged =\r\n !prev ||\r\n prev.deps.length !== deps.length ||\r\n deps.some((dep, i) => !Object.is(dep, prev.deps[i]));\r\n\r\n if (hasChanged) {\r\n try {\r\n const value = factory();\r\n ctx.hooks[idx] = { value, deps: [...deps] };\r\n } catch (err) {\r\n console.error(\"[nixMemo] Factory function error:\", err);\r\n ctx.hooks[idx] = { value: undefined as unknown as T, deps: [...deps] };\r\n }\r\n }\r\n\r\n return (ctx.hooks[idx] as MemoHook | undefined)?.value;\r\n}\r\n"],
5
- "mappings": ";;AAsBA,SAAS,qBAAqB;AASvB,SAAS,QAAW,SAAkB,OAAc,CAAC,GAAkB;AAE5E,QAAM,MAAM;AAMZ,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,oCAAoC;AAE9D,MAAI,OAAO,YAAY,YAAY;AACjC,YAAQ,MAAM,6CAA6C;AAC3D,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,MAAM,QAAQ,IAAI,GAAG;AACxB,YAAQ,MAAM,4CAA4C;AAC1D,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,MAAc,IAAI;AACxB,QAAM,OAAO,IAAI,MAAM,GAAG;AAE1B,QAAM,aACJ,CAAC,QACD,KAAK,KAAK,WAAW,KAAK,UAC1B,KAAK,KAAK,CAAC,KAAK,MAAM,CAAC,OAAO,GAAG,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC;AAErD,MAAI,YAAY;AACd,QAAI;AACF,YAAM,QAAQ,QAAQ;AACtB,UAAI,MAAM,GAAG,IAAI,EAAE,OAAO,MAAM,CAAC,GAAG,IAAI,EAAE;AAAA,IAC5C,SAAS,KAAK;AACZ,cAAQ,MAAM,qCAAqC,GAAG;AACtD,UAAI,MAAM,GAAG,IAAI,EAAE,OAAO,QAA2B,MAAM,CAAC,GAAG,IAAI,EAAE;AAAA,IACvE;AAAA,EACF;AAEA,SAAQ,IAAI,MAAM,GAAG,GAA4B;AACnD;AAvCgB;",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"nixPrevious.d.ts","sourceRoot":"","sources":["../../hooks/nixPrevious.ts"],"names":[],"mappings":"AA8CA,wBAAgB,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS,CAiBpD"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixPrevious.ts"],
4
- "sourcesContent": ["/* MIT License\r\n\r\n* Copyright (c) 2026 Resty Gonzales\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n* SOFTWARE.\r\n */\r\n/**\r\n * @fileoverview Hook to track previous value across renders.\r\n * Useful for comparing current and previous state.\r\n */\r\n\r\nimport { activeContext } from \"../context/context\";\r\n\r\n/**\r\n * Returns the previous value of a variable across renders.\r\n * Useful for detecting changes and implementing undo functionality.\r\n *\r\n * @template T\r\n * @param {T} val - Current value\r\n * @returns {T | undefined} Previous value (undefined on first render)\r\n *\r\n * @example\r\n * const count = nixState(0);\r\n * const prevCount = nixPrevious(count.value);\r\n *\r\n * // prevCount will be undefined on first render\r\n * // then will hold the previous value on subsequent renders\r\n *\r\n * @throws {Error} If called outside a component context\r\n */\r\nexport function nixPrevious<T>(val: T): T | undefined {\r\n const ctx = activeContext as {\r\n hookIndex: number;\r\n hooks: Array<{ value: T } | undefined>;\r\n };\r\n if (!ctx) throw new Error(\"nixPrevious() called outside component\");\r\n\r\n const idx: number = ctx.hookIndex++;\r\n const prev: T | undefined = ctx.hooks[idx]?.value;\r\n\r\n try {\r\n ctx.hooks[idx] = { value: val };\r\n } catch (err) {\r\n console.error(\"[nixPrevious] Error storing value:\", err);\r\n }\r\n\r\n return prev;\r\n}\r\n"],
5
- "mappings": ";;AA2BA,SAAS,qBAAqB;AAmBvB,SAAS,YAAe,KAAuB;AACpD,QAAM,MAAM;AAIZ,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,wCAAwC;AAElE,QAAM,MAAc,IAAI;AACxB,QAAM,OAAsB,IAAI,MAAM,GAAG,GAAG;AAE5C,MAAI;AACF,QAAI,MAAM,GAAG,IAAI,EAAE,OAAO,IAAI;AAAA,EAChC,SAAS,KAAK;AACZ,YAAQ,MAAM,sCAAsC,GAAG;AAAA,EACzD;AAEA,SAAO;AACT;AAjBgB;",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"nixRef.d.ts","sourceRoot":"","sources":["../../hooks/nixRef.ts"],"names":[],"mappings":"AA+BA,wBAAgB,MAAM,CAAC,CAAC,GAAG,GAAG,EAAE,OAAO,GAAE,CAAe,GAAG;IAAE,OAAO,EAAE,CAAC,CAAA;CAAE,CAsBxE"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixRef.ts"],
4
- "sourcesContent": ["/* MIT License\r\n\r\n* Copyright (c) 2026 Resty Gonzales\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n* SOFTWARE.\r\n */\r\nimport { activeContext } from \"../context/context\";\r\n\r\n/**\r\n * Returns a mutable ref object that persists across renders.\r\n * Similar to React's useRef.\r\n *\r\n * @param {any} initial - Initial value for the ref\r\n * @returns {{ current: any }} Ref object\r\n */\r\nexport function nixRef<T = any>(initial: T = null as any): { current: T } {\r\n type RefHook = { current: T };\r\n const ctx = activeContext as\r\n | (typeof activeContext & {\r\n hookIndex: number;\r\n hooks: Array<RefHook | undefined>;\r\n })\r\n | undefined;\r\n if (!ctx) throw new Error(\"nixRef() called outside component\");\r\n\r\n const idx: number = ctx.hookIndex++;\r\n\r\n if (!ctx.hooks[idx]) {\r\n try {\r\n ctx.hooks[idx] = { current: initial };\r\n } catch (err) {\r\n console.error(\"[nixRef] Error initializing ref:\", err);\r\n ctx.hooks[idx] = { current: null as any };\r\n }\r\n }\r\n\r\n return ctx.hooks[idx] as RefHook;\r\n}\r\n"],
5
- "mappings": ";;AAsBA,SAAS,qBAAqB;AASvB,SAAS,OAAgB,UAAa,MAA6B;AAExE,QAAM,MAAM;AAMZ,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,mCAAmC;AAE7D,QAAM,MAAc,IAAI;AAExB,MAAI,CAAC,IAAI,MAAM,GAAG,GAAG;AACnB,QAAI;AACF,UAAI,MAAM,GAAG,IAAI,EAAE,SAAS,QAAQ;AAAA,IACtC,SAAS,KAAK;AACZ,cAAQ,MAAM,oCAAoC,GAAG;AACrD,UAAI,MAAM,GAAG,IAAI,EAAE,SAAS,KAAY;AAAA,IAC1C;AAAA,EACF;AAEA,SAAO,IAAI,MAAM,GAAG;AACtB;AAtBgB;",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"nixState.d.ts","sourceRoot":"","sources":["../../hooks/nixState.ts"],"names":[],"mappings":"AAkEA,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG;IACvC,KAAK,EAAE,CAAC,CAAC;IACT,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAClD,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,kBAAkB,EAAE,MAAM,MAAM,CAAC;IACjC,WAAW,EAAE,MAAM,OAAO,CAAC;IAC3B,UAAU,EAAE,MAAM;QAChB,KAAK,EAAE,CAAC,CAAC;QACT,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;QAClD,WAAW,EAAE,IAAI,CAAC;QAClB,WAAW,EAAE,IAAI,CAAC;KACnB,CAAC;IACF,WAAW,EAAE,IAAI,CAAC;CACnB,CAgJA"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixState.ts"],
4
- "sourcesContent": ["/* MIT License\r\n\r\n* Copyright (c) 2026 Resty Gonzales\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n* SOFTWARE.\r\n */\r\n/* ----------------------\r\n nixState - Reactive State\r\n Memory Leaks & Security Issues Resolved\r\n---------------------- */\r\nimport { activeContext } from \"../context/context\";\r\n\r\n/**\r\n * Creates a reactive state value that triggers component re-renders when changed.\r\n * Must be called within a component function.\r\n *\r\n * @param {any} initial - The initial value for the state\r\n * @returns {NixState} A reactive state object with value getter/setter and subscription methods\r\n *\r\n * @typedef {Object} NixState\r\n * @property {any} value - Get/set the current state value. Getting tracks the dependency, setting triggers subscribers.\r\n * @property {(fn: Function) => Function} subscribe - Subscribe to state changes. Returns unsubscribe function.\r\n * @property {() => void} cleanup - Cleanup all subscriptions to prevent memory leaks\r\n * @property {() => number} getSubscriberCount - Get number of active subscribers (debugging)\r\n * @property {() => boolean} isDestroyed - Check if state has been destroyed\r\n * @property {() => Object} asReadOnly - Get read-only version of the state\r\n * @property {boolean} _isNixState - Internal flag to identify nixState objects\r\n *\r\n * @example\r\n * const Counter = () => {\r\n * const count = nixState(0);\r\n *\r\n * return h(\"div\", {},\r\n * h(\"p\", {}, \"Count: \", count),\r\n * h(\"button\", { \"r-click\": () => count.value++ }, \"Increment\")\r\n * );\r\n * };\r\n *\r\n * @example\r\n * // With cleanup\r\n * const MyComponent = () => {\r\n * const state = nixState(0);\r\n *\r\n * nixEffect(() => {\r\n * return () => state.cleanup(); // Clean up on unmount\r\n * }, []);\r\n * };\r\n *\r\n * @throws {Error} If called outside a component context\r\n */\r\nexport function nixState<T>(initial: T): {\r\n value: T;\r\n subscribe: (fn: (value: T) => void) => () => void;\r\n cleanup: () => void;\r\n getSubscriberCount: () => number;\r\n isDestroyed: () => boolean;\r\n asReadOnly: () => {\r\n value: T;\r\n subscribe: (fn: (value: T) => void) => () => void;\r\n _isNixState: true;\r\n _isReadOnly: true;\r\n };\r\n _isNixState: true;\r\n} {\r\n const ctx = activeContext as\r\n | (typeof activeContext & {\r\n hookIndex: number;\r\n hooks: Array<any>;\r\n stateCleanups?: Array<() => void>;\r\n })\r\n | undefined;\r\n if (!ctx) throw new Error(\"nixState() called outside component\");\r\n\r\n const idx = ctx.hookIndex++;\r\n if (!ctx.hooks[idx]) {\r\n let value: T = initial;\r\n const subscribers: Set<(value: T) => void> = new Set();\r\n let isDestroyed = false;\r\n\r\n // Security: Validate initial value to prevent prototype pollution\r\n if (initial !== null && typeof initial === \"object\") {\r\n if (\r\n \"__proto__\" in (initial as any) ||\r\n \"constructor\" in (initial as any) ||\r\n \"prototype\" in (initial as any)\r\n ) {\r\n // Create a clean copy without dangerous properties\r\n if (Array.isArray(initial)) {\r\n value = [...(initial as any)] as T;\r\n } else {\r\n value = { ...(initial as any) };\r\n delete (value as any).__proto__;\r\n delete (value as any).constructor;\r\n delete (value as any).prototype;\r\n }\r\n }\r\n }\r\n\r\n const s = {\r\n get value(): T {\r\n if (isDestroyed) {\r\n /* console.warn(\"[nixState] Accessing destroyed state\"); */\r\n return value;\r\n }\r\n if (activeContext && !isDestroyed) {\r\n activeContext._accessedStates.add(s);\r\n }\r\n return value;\r\n },\r\n set value(newVal: T) {\r\n if (isDestroyed) {\r\n /* console.warn(\"[nixState] Attempting to update destroyed state\"); */\r\n return;\r\n }\r\n if (newVal === value) return;\r\n if (newVal !== null && typeof newVal === \"object\") {\r\n if (\r\n \"__proto__\" in (newVal as any) ||\r\n \"constructor\" in (newVal as any) ||\r\n \"prototype\" in (newVal as any)\r\n ) {\r\n /* console.warn(\r\n \"[nixState] Security: Dangerous properties detected in new value\"\r\n ); */\r\n if (Array.isArray(newVal)) {\r\n newVal = [...(newVal as any)] as T;\r\n } else {\r\n newVal = { ...(newVal as any) };\r\n delete (newVal as any).__proto__;\r\n delete (newVal as any).constructor;\r\n delete (newVal as any).prototype;\r\n }\r\n }\r\n }\r\n value = newVal;\r\n const subsArray = Array.from(subscribers);\r\n subsArray.forEach((fn) => {\r\n try {\r\n fn(newVal);\r\n } catch (err) {\r\n console.error(\"[nixState] Subscriber error:\", err);\r\n subscribers.delete(fn);\r\n }\r\n });\r\n },\r\n subscribe(fn: (value: T) => void): () => void {\r\n if (typeof fn !== \"function\") {\r\n console.error(\"[nixState] subscribe() requires a function\");\r\n return () => {};\r\n }\r\n if (isDestroyed) {\r\n console.warn(\"[nixState] Cannot subscribe to destroyed state\");\r\n return () => {};\r\n }\r\n const MAX_SUBSCRIBERS = 1000;\r\n if (subscribers.size >= MAX_SUBSCRIBERS) {\r\n console.error(\"[nixState] Maximum subscriber limit reached\");\r\n return () => {};\r\n }\r\n subscribers.add(fn);\r\n return () => {\r\n subscribers.delete(fn);\r\n };\r\n },\r\n cleanup(): void {\r\n if (isDestroyed) return;\r\n isDestroyed = true;\r\n subscribers.clear();\r\n if (value !== null && typeof value === \"object\") {\r\n if (Array.isArray(value)) {\r\n value = [] as any as T;\r\n } else {\r\n value = null as any as T;\r\n }\r\n }\r\n console.log(\"[nixState] State cleaned up\");\r\n },\r\n getSubscriberCount(): number {\r\n return subscribers.size;\r\n },\r\n isDestroyed(): boolean {\r\n return isDestroyed;\r\n },\r\n asReadOnly(): {\r\n value: T;\r\n subscribe: (fn: (value: T) => void) => () => void;\r\n _isNixState: true;\r\n _isReadOnly: true;\r\n } {\r\n return {\r\n get value() {\r\n return s.value;\r\n },\r\n subscribe: s.subscribe.bind(s),\r\n _isNixState: true,\r\n _isReadOnly: true,\r\n };\r\n },\r\n _isNixState: true as const,\r\n };\r\n\r\n ctx.hooks[idx] = s;\r\n if (ctx.stateCleanups) {\r\n ctx.stateCleanups.push(() => s.cleanup());\r\n }\r\n }\r\n return ctx.hooks[idx] as ReturnType<typeof nixState<T>>;\r\n}\r\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"nixStore.d.ts","sourceRoot":"","sources":["../../hooks/nixStore.ts"],"names":[],"mappings":"AAkCA,wBAAgB,QAAQ,CAAC,CAAC,GAAG,GAAG,EAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,GACT;IACD,KAAK,EAAE,CAAC,CAAC;IACT,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,kBAAkB,EAAE,MAAM,MAAM,CAAC;IACjC,WAAW,EAAE,MAAM,OAAO,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;CACtB,CAkJA"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../hooks/nixStore.ts"],
4
- "sourcesContent": ["/* MIT License\r\n\r\n* Copyright (c) 2026 Resty Gonzales\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n* SOFTWARE.\r\n */\r\nimport { activeContext } from \"../context/context\";\r\n\r\n/**\r\n * Reactive store hook with subscription support and enhanced security.\r\n * Memory-safe: cleans up subscribers on component unmount.\r\n * Prevents prototype pollution and validates inputs.\r\n *\r\n * @template T\r\n * @param {string} path - Path identifier (required, must be safe)\r\n * @param {T} initial - Initial value\r\n * @returns {Object} Reactive store object with get/set/subscribe\r\n */\r\nexport function nixStore<T = any>(\r\n path: string,\r\n initial: T\r\n): {\r\n value: T;\r\n subscribe: (fn: () => void) => () => void;\r\n path: string;\r\n cleanup: () => void;\r\n getSubscriberCount: () => number;\r\n isDestroyed: () => boolean;\r\n _isNixState: boolean;\r\n} {\r\n // Input validation\r\n if (!path || typeof path !== \"string\") {\r\n throw new Error(\"[nixStore] Path must be a non-empty string\");\r\n }\r\n\r\n // Validate path for security (prevent prototype pollution)\r\n const dangerousKeys = [\"__proto__\", \"constructor\", \"prototype\"];\r\n if (dangerousKeys.some((key) => path.includes(key))) {\r\n throw new Error(\"[nixStore] Path contains dangerous keywords\");\r\n }\r\n\r\n if (path.length > 200) {\r\n throw new Error(\"[nixStore] Path too long (max 200 characters)\");\r\n }\r\n\r\n type StoreHook = {\r\n value: T;\r\n subscribe: (fn: () => void) => () => void;\r\n path: string;\r\n cleanup: () => void;\r\n getSubscriberCount: () => number;\r\n isDestroyed: () => boolean;\r\n _isNixState: boolean;\r\n };\r\n\r\n const ctx = activeContext as\r\n | (typeof activeContext & {\r\n hookIndex: number;\r\n hooks: Array<StoreHook | undefined>;\r\n cleanups?: Array<() => void>;\r\n })\r\n | undefined;\r\n if (!ctx) throw new Error(\"nixStore() called outside component\");\r\n\r\n const idx: number = ctx.hookIndex++;\r\n\r\n if (!ctx.hooks[idx]) {\r\n let value: T = initial;\r\n const subscribers: Set<() => void> = new Set();\r\n let isDestroyed = false;\r\n let maxSubscribers = 100; // Prevent memory leaks\r\n\r\n const s: StoreHook = {\r\n get value() {\r\n if (isDestroyed) {\r\n console.warn(\"[nixStore] Accessing destroyed store:\", path);\r\n return value;\r\n }\r\n\r\n try {\r\n if ((activeContext as any)?._accessedStates) {\r\n (activeContext as any)._accessedStates.add(s);\r\n }\r\n } catch (err) {\r\n console.error(\"[nixStore] Error tracking accessed state:\", err);\r\n }\r\n return value;\r\n },\r\n set value(v: T) {\r\n if (isDestroyed) {\r\n console.warn(\r\n \"[nixStore] Attempting to set value on destroyed store:\",\r\n path\r\n );\r\n return;\r\n }\r\n\r\n // Validate value for security\r\n if (v && typeof v === \"object\") {\r\n // Create safe object without dangerous properties\r\n const safeValue = Object.create(null);\r\n for (const key in v) {\r\n if (\r\n Object.prototype.hasOwnProperty.call(v, key) &&\r\n !dangerousKeys.includes(key)\r\n ) {\r\n safeValue[key] = v[key];\r\n }\r\n }\r\n value = safeValue as T;\r\n } else {\r\n value = v;\r\n }\r\n\r\n // Notify subscribers safely\r\n const subscriberArray = Array.from(subscribers);\r\n subscriberArray.forEach((fn) => {\r\n try {\r\n fn();\r\n } catch (err) {\r\n console.error(\"[nixStore] Subscriber error:\", err);\r\n // Remove failing subscriber to prevent repeated errors\r\n subscribers.delete(fn);\r\n }\r\n });\r\n },\r\n subscribe(fn: () => void) {\r\n if (isDestroyed) {\r\n console.warn(\r\n \"[nixStore] Attempting to subscribe to destroyed store:\",\r\n path\r\n );\r\n return () => {};\r\n }\r\n\r\n if (typeof fn !== \"function\") {\r\n console.error(\"[nixStore] Subscriber must be a function\");\r\n return () => {};\r\n }\r\n\r\n if (subscribers.size >= maxSubscribers) {\r\n console.warn(\r\n `[nixStore] Maximum subscribers (${maxSubscribers}) reached for store:`,\r\n path\r\n );\r\n return () => {};\r\n }\r\n\r\n subscribers.add(fn);\r\n // Return cleanup function\r\n return () => {\r\n subscribers.delete(fn);\r\n };\r\n },\r\n cleanup() {\r\n if (isDestroyed) return;\r\n\r\n isDestroyed = true;\r\n subscribers.clear();\r\n console.debug(`[nixStore] Cleaned up store: ${path}`);\r\n },\r\n getSubscriberCount: () => subscribers.size,\r\n isDestroyed: () => isDestroyed,\r\n path,\r\n _isNixState: true,\r\n };\r\n\r\n // Register cleanup on component unmount\r\n if (!ctx.cleanups) ctx.cleanups = [];\r\n ctx.cleanups.push(() => s.cleanup());\r\n\r\n ctx.hooks[idx] = s;\r\n }\r\n\r\n return ctx.hooks[idx] as StoreHook;\r\n}\r\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"vite-plugin-res.d.ts","sourceRoot":"","sources":["../../plugins/vite-plugin-res.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAMtD,UAAU,kBAAkB;IAK1B,UAAU,CAAC,EAAE,MAAM,CAAC;IAMpB,WAAW,CAAC,EAAE,MAAM,CAAC;IAMrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAMnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAMnB,SAAS,CAAC,EAAE,OAAO,CAAC;IAKpB,cAAc,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC5C;AAaD,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,OAAO,GAAE,kBAAuB;;;4BAoBxC,aAAa;oBAIf,MAAM,MAAM,MAAM;;;;yBAqEnB,UAAU;;;;;;;;;;;;;;;;EA0ClC;AAKD,OAAO,EAAE,WAAW,EAAE,CAAC;AAKvB,YAAY,EAAE,kBAAkB,EAAE,CAAC"}
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../plugins/vite-plugin-res.ts"],
4
- "sourcesContent": ["import { transform, type TransformOptions } from \"esbuild\";\r\nimport type { HmrContext, ViteDevServer } from \"vite\";\r\nimport { normalizePath } from \"vite\";\r\n\r\n/**\r\n * Vite plugin options for Fynix\r\n */\r\ninterface FynixPluginOptions {\r\n /**\r\n * JSX factory function name\r\n * @default \"Fynix\"\r\n */\r\n jsxFactory?: string;\r\n\r\n /**\r\n * JSX fragment factory name\r\n * @default \"Fynix.Fragment\"\r\n */\r\n jsxFragment?: string;\r\n\r\n /**\r\n * File extensions to transform\r\n * @default [\".ts\", \".js\", \".jsx\", \".tsx\", \".fnx\"]\r\n */\r\n include?: string[];\r\n\r\n /**\r\n * Paths to exclude from transformation\r\n * @default [\"node_modules\"]\r\n */\r\n exclude?: string[];\r\n\r\n /**\r\n * Enable source maps\r\n * @default true\r\n */\r\n sourcemap?: boolean;\r\n\r\n /**\r\n * Custom esbuild transform options\r\n */\r\n esbuildOptions?: Partial<TransformOptions>;\r\n}\r\n\r\n/**\r\n * Extended context type that includes Vite's transform context methods\r\n */\r\ninterface TransformContext {\r\n addWatchFile?: (id: string) => void;\r\n}\r\n\r\n/**\r\n * Vite plugin for Fynix framework\r\n * Transforms JSX/TSX files using esbuild with custom JSX pragma\r\n */\r\nexport default function fynixPlugin(options: FynixPluginOptions = {}) {\r\n const {\r\n jsxFactory = \"Fynix\",\r\n jsxFragment = \"Fynix.Fragment\",\r\n include = [\".ts\", \".js\", \".jsx\", \".tsx\", \".fnx\"],\r\n exclude = [\"node_modules\"],\r\n sourcemap = true,\r\n esbuildOptions = {},\r\n } = options;\r\n\r\n let viteServer: ViteDevServer | null = null;\r\n\r\n return {\r\n name: \"vite-plugin-fynix\",\r\n enforce: \"pre\" as const,\r\n\r\n /**\r\n * Capture the Vite dev server instance for sending\r\n * WebSocket messages (error overlays, reloads, etc.)\r\n */\r\n configureServer(server: ViteDevServer) {\r\n viteServer = server;\r\n },\r\n\r\n async transform(code: string, id: string) {\r\n const normalizedId = normalizePath(id);\r\n const shouldExclude = exclude.some((pattern) =>\r\n normalizedId.includes(pattern)\r\n );\r\n if (shouldExclude) return null;\r\n const shouldInclude = include.some((ext) => normalizedId.endsWith(ext));\r\n if (!shouldInclude) return null;\r\n\r\n // Type-safe way to access Vite context methods\r\n const ctx = this as unknown as TransformContext;\r\n if (typeof ctx.addWatchFile === \"function\") {\r\n ctx.addWatchFile(id);\r\n }\r\n\r\n try {\r\n let loader: TransformOptions[\"loader\"] = \"tsx\";\r\n if (normalizedId.endsWith(\".ts\") || normalizedId.endsWith(\".fnx\")) {\r\n loader = \"tsx\";\r\n } else if (normalizedId.endsWith(\".tsx\")) {\r\n loader = \"tsx\";\r\n } else if (normalizedId.endsWith(\".jsx\")) {\r\n loader = \"jsx\";\r\n } else if (normalizedId.endsWith(\".js\")) {\r\n loader = \"jsx\";\r\n }\r\n\r\n const result = await transform(code, {\r\n loader,\r\n jsxFactory,\r\n jsxFragment,\r\n sourcemap,\r\n sourcefile: id,\r\n target: \"esnext\",\r\n format: \"esm\",\r\n ...esbuildOptions,\r\n });\r\n\r\n return {\r\n code: result.code,\r\n map: result.map || null,\r\n };\r\n } catch (error) {\r\n const err = error as Error;\r\n\r\n // Send error overlay to the browser via WebSocket\r\n // This shows the red error overlay in the browser instead of just logging to terminal\r\n if (viteServer) {\r\n viteServer.ws.send({\r\n type: \"error\",\r\n err: {\r\n message: err.message,\r\n stack: err.stack || \"\",\r\n plugin: \"vite-plugin-fynix\",\r\n id,\r\n },\r\n });\r\n }\r\n\r\n // Log to terminal as well\r\n console.error(`\\x1b[32m[vite-plugin-fynix]\\x1b[0m \\x1b[31mFailed to transform ${id}:\\x1b[0m`);\r\n console.error(err.message);\r\n\r\n // Return null instead of throwing so Vite's HMR pipeline\r\n // stays intact and can recover when the error is fixed\r\n return null;\r\n }\r\n },\r\n\r\n handleHotUpdate(ctx: HmrContext) {\r\n const { file, server } = ctx;\r\n const normalizedFile = normalizePath(file);\r\n const shouldReload = include.some((ext) => normalizedFile.endsWith(ext));\r\n\r\n if (shouldReload) {\r\n console.log(\r\n `\\x1b[32m[vite-plugin-fynix]\\x1b[0m HMR: full-reload triggered by ${normalizedFile}`\r\n );\r\n server.ws.send({\r\n type: \"full-reload\",\r\n path: \"*\",\r\n });\r\n return [];\r\n }\r\n\r\n return undefined;\r\n },\r\n\r\n config() {\r\n return {\r\n esbuild: false as const,\r\n optimizeDeps: {\r\n include: [\"fynixui\"],\r\n esbuildOptions: {\r\n jsx: \"transform\",\r\n jsxFactory,\r\n jsxFragment,\r\n },\r\n },\r\n resolve: {\r\n extensions: [\".fnx\", \".ts\", \".tsx\", \".js\", \".jsx\", \".json\"],\r\n },\r\n };\r\n },\r\n\r\n buildStart() {\r\n console.log(\r\n `\\x1b[32m[vite-plugin-fynix]\\x1b[0m Initialized with JSX factory: ${jsxFactory}`\r\n );\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Named export for convenience\r\n */\r\nexport { fynixPlugin };\r\n\r\n/**\r\n * Export types for TypeScript users\r\n */\r\nexport type { FynixPluginOptions };\r\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../router/router.ts"],"names":[],"mappings":"AA2DA,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,iBAAiB,CAAC;IAC7B,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,iBAAiB;IACzB,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG,CAAC;CACnB;AAED,UAAU,cAAc;IACtB,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1D,IAAI,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC;CACpE;AAED,UAAU,SAAS;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,cAAc,CAAC;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAaD,UAAU,WAAW;IACnB,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IAC1D,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACzD,IAAI,IAAI,IAAI,CAAC;IACb,OAAO,IAAI,IAAI,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACvC,aAAa,EAAE,YAAY,EAAE,CAAC;IAE9B,YAAY,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,UAAU,CAAC,IAAI,IAAI,CAAC;IACpB,mBAAmB,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;CACnD;AA0pBD,iBAAS,WAAW,IAAI,WAAW,CAmjBlC;AAGD,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,eAAe,WAAW,CAAC;AAM3B,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAqB1E;AAKD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAoBhD"}