@fynixorg/ui 1.0.5 → 1.0.7

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.
@@ -1,11 +1,22 @@
1
1
  /**
2
2
  * Reactive wrapper around localStorage with safe JSON parsing/stringifying.
3
+ * Automatically persists state changes to localStorage.
3
4
  *
5
+ * @template T
4
6
  * @param {string} key - LocalStorage key
5
- * @param {any} initial - Initial value if key does not exist
6
- * @returns {{ value: any, set: (v: any) => void }}
7
+ * @param {T} initial - Initial value if key does not exist
8
+ * @returns {{ value: T, set: (v: T) => void }} Object with value getter and setter
9
+ *
10
+ * @example
11
+ * const theme = nixLocalStorage('theme', 'light');
12
+ * console.log(theme.value); // 'light' or stored value
13
+ * theme.set('dark'); // Updates state and localStorage
14
+ *
15
+ * @example
16
+ * const user = nixLocalStorage('user', { name: '', age: 0 });
17
+ * user.set({ name: 'John', age: 30 });
7
18
  */
8
- export function nixLocalStorage(key: string, initial: any): {
9
- value: any;
10
- set: (v: any) => void;
19
+ export function nixLocalStorage<T>(key: string, initial: T): {
20
+ value: T;
21
+ set: (v: T) => void;
11
22
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../hooks/nixLocalStorage.js"],
4
- "sourcesContent": ["import { nixState } from \"./nixState\";\r\n\r\n/**\r\n * Reactive wrapper around localStorage with safe JSON parsing/stringifying.\r\n *\r\n * @param {string} key - LocalStorage key\r\n * @param {any} initial - Initial value if key does not exist\r\n * @returns {{ value: any, set: (v: any) => void }}\r\n */\r\nexport function nixLocalStorage(key, initial) {\r\n const s = nixState(() => {\r\n try {\r\n const v = localStorage.getItem(key);\r\n if (v != null) return JSON.parse(v);\r\n return initial;\r\n } catch (err) {\r\n console.error(`[nixLocalStorage] Error reading key \"${key}\":`, err);\r\n return initial;\r\n }\r\n });\r\n\r\n const set = (v) => {\r\n s.value = v;\r\n try {\r\n localStorage.setItem(key, JSON.stringify(v));\r\n } catch (err) {\r\n console.error(`[nixLocalStorage] Error setting key \"${key}\":`, err);\r\n }\r\n };\r\n\r\n return { value: s.value, set };\r\n}\r\n"],
5
- "mappings": ";;AAAA,SAAS,gBAAgB;AASlB,SAAS,gBAAgB,KAAK,SAAS;AAC5C,QAAM,IAAI,SAAS,MAAM;AACvB,QAAI;AACF,YAAM,IAAI,aAAa,QAAQ,GAAG;AAClC,UAAI,KAAK;AAAM,eAAO,KAAK,MAAM,CAAC;AAClC,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,cAAQ,MAAM,wCAAwC,GAAG,MAAM,GAAG;AAClE,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAED,QAAM,MAAM,wBAAC,MAAM;AACjB,MAAE,QAAQ;AACV,QAAI;AACF,mBAAa,QAAQ,KAAK,KAAK,UAAU,CAAC,CAAC;AAAA,IAC7C,SAAS,KAAK;AACZ,cAAQ,MAAM,wCAAwC,GAAG,MAAM,GAAG;AAAA,IACpE;AAAA,EACF,GAPY;AASZ,SAAO,EAAE,OAAO,EAAE,OAAO,IAAI;AAC/B;AAtBgB;",
4
+ "sourcesContent": ["/**\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 * 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 }} Object with value getter and setter\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(key, initial) {\r\n const s = nixState(() => {\r\n try {\r\n const v = localStorage.getItem(key);\r\n if (v != null) return JSON.parse(v);\r\n return initial;\r\n } catch (err) {\r\n console.error(`[nixLocalStorage] Error reading key \"${key}\":`, err);\r\n return initial;\r\n }\r\n });\r\n\r\n const set = (v) => {\r\n s.value = v;\r\n try {\r\n localStorage.setItem(key, JSON.stringify(v));\r\n } catch (err) {\r\n console.error(`[nixLocalStorage] Error setting key \"${key}\":`, err);\r\n }\r\n };\r\n\r\n return { value: s.value, set };\r\n}\r\n"],
5
+ "mappings": ";;AAKA,SAAS,gBAAgB;AAoBlB,SAAS,gBAAgB,KAAK,SAAS;AAC5C,QAAM,IAAI,SAAS,MAAM;AACvB,QAAI;AACF,YAAM,IAAI,aAAa,QAAQ,GAAG;AAClC,UAAI,KAAK;AAAM,eAAO,KAAK,MAAM,CAAC;AAClC,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,cAAQ,MAAM,wCAAwC,GAAG,MAAM,GAAG;AAClE,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAED,QAAM,MAAM,wBAAC,MAAM;AACjB,MAAE,QAAQ;AACV,QAAI;AACF,mBAAa,QAAQ,KAAK,KAAK,UAAU,CAAC,CAAC;AAAA,IAC7C,SAAS,KAAK;AACZ,cAAQ,MAAM,wCAAwC,GAAG,MAAM,GAAG;AAAA,IACpE;AAAA,EACF,GAPY;AASZ,SAAO,EAAE,OAAO,EAAE,OAAO,IAAI;AAC/B;AAtBgB;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,18 @@
1
1
  /**
2
2
  * Returns the previous value of a variable across renders.
3
+ * Useful for detecting changes and implementing undo functionality.
3
4
  *
4
- * @param {any} val - Current value
5
- * @returns {any} Previous value
5
+ * @template T
6
+ * @param {T} val - Current value
7
+ * @returns {T | undefined} Previous value (undefined on first render)
8
+ *
9
+ * @example
10
+ * const count = nixState(0);
11
+ * const prevCount = nixPrevious(count.value);
12
+ *
13
+ * // prevCount will be undefined on first render
14
+ * // then will hold the previous value on subsequent renders
15
+ *
16
+ * @throws {Error} If called outside a component context
6
17
  */
7
- export function nixPrevious(val: any): any;
18
+ export function nixPrevious<T>(val: T): T | undefined;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../hooks/nixPrevious.js"],
4
- "sourcesContent": ["import { activeContext } from \"../context/context\";\r\n\r\n/**\r\n * Returns the previous value of a variable across renders.\r\n *\r\n * @param {any} val - Current value\r\n * @returns {any} Previous value\r\n */\r\nexport function nixPrevious(val) {\r\n const ctx = activeContext;\r\n if (!ctx) throw new Error(\"nixPrevious() called outside component\");\r\n\r\n const idx = ctx.hookIndex++;\r\n const prev = 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": ";;AAAA,SAAS,qBAAqB;AAQvB,SAAS,YAAY,KAAK;AAC/B,QAAM,MAAM;AACZ,MAAI,CAAC;AAAK,UAAM,IAAI,MAAM,wCAAwC;AAElE,QAAM,MAAM,IAAI;AAChB,QAAM,OAAO,IAAI,MAAM,GAAG,GAAG;AAE7B,MAAI;AACF,QAAI,MAAM,GAAG,IAAI,EAAE,OAAO,IAAI;AAAA,EAChC,SAAS,KAAK;AACZ,YAAQ,MAAM,sCAAsC,GAAG;AAAA,EACzD;AAEA,SAAO;AACT;AAdgB;",
4
+ "sourcesContent": ["/**\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(val) {\r\n const ctx = activeContext;\r\n if (!ctx) throw new Error(\"nixPrevious() called outside component\");\r\n\r\n const idx = ctx.hookIndex++;\r\n const prev = 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": ";;AAKA,SAAS,qBAAqB;AAmBvB,SAAS,YAAY,KAAK;AAC/B,QAAM,MAAM;AACZ,MAAI,CAAC;AAAK,UAAM,IAAI,MAAM,wCAAwC;AAElE,QAAM,MAAM,IAAI;AAChB,QAAM,OAAO,IAAI,MAAM,GAAG,GAAG;AAE7B,MAAI;AACF,QAAI,MAAM,GAAG,IAAI,EAAE,OAAO,IAAI;AAAA,EAChC,SAAS,KAAK;AACZ,YAAQ,MAAM,sCAAsC,GAAG;AAAA,EACzD;AAEA,SAAO;AACT;AAdgB;",
6
6
  "names": []
7
7
  }
@@ -1,12 +1,16 @@
1
- export function fynix(): {
2
- name: string;
3
- enforce: string;
4
- transform(code: any, id: any): Promise<{
5
- code: string;
6
- map: string;
7
- }>;
8
- handleHotUpdate({ file, server }: {
9
- file: any;
10
- server: any;
11
- }): any[];
12
- };
1
+ /**
2
+ * Vite plugin for transforming Fynix JSX files.
3
+ * Automatically transforms .js and .fnx files.
4
+ *
5
+ * @returns {Object} Vite plugin object
6
+ *
7
+ * @example
8
+ * // vite.config.js
9
+ * import { defineConfig } from 'vite';
10
+ * import { fynix } from '@fynixorg/ui/plugins/vite-plugin-fynix';
11
+ *
12
+ * export default defineConfig({
13
+ * plugins: [fynix()]
14
+ * });
15
+ */
16
+ export function fynix(): any;
@@ -2,29 +2,89 @@ var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
  import { transform } from "esbuild";
4
4
  function fynix() {
5
+ const failedFiles = /* @__PURE__ */ new Set();
6
+ const COMPILE_SUCCESS_COLOR = "\x1B[32m";
7
+ const COMPILE_ERROR_COLOR = "\x1B[31m";
8
+ const RESET_COLOR = "\x1B[0m";
9
+ const BOLD = "\x1B[1m";
5
10
  return {
6
- name: "vite-plugin-res",
11
+ name: "vite-plugin-fynix",
7
12
  enforce: "pre",
8
13
  async transform(code, id) {
9
- if (!id.includes("/src/"))
14
+ if (!/\.(js|fnx)$/.test(id) || /node_modules/.test(id)) {
10
15
  return null;
11
- if (!id.endsWith(".ts") && !id.endsWith(".js") && !id.endsWith(".fnx"))
12
- return null;
13
- this.addWatchFile(id);
14
- const result = await transform(code, {
15
- loader: "jsx",
16
- jsxFactory: "Fynix",
17
- jsxFragment: "Fynix.Fragment",
18
- sourcemap: true,
19
- sourcefile: id
20
- });
21
- return {
22
- code: result.code,
23
- map: result.map
24
- };
16
+ }
17
+ try {
18
+ const result = await transform(code, {
19
+ loader: "tsx",
20
+ jsxFactory: "Fynix",
21
+ jsxFragment: "Fynix.Fragment",
22
+ sourcemap: true,
23
+ sourcefile: id,
24
+ target: "es2020"
25
+ });
26
+ if (failedFiles.has(id)) {
27
+ failedFiles.delete(id);
28
+ const fileName = id.split("/").pop();
29
+ const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString();
30
+ console.log(
31
+ `${COMPILE_SUCCESS_COLOR}\u2713${RESET_COLOR} ${BOLD}${fileName}${RESET_COLOR} ${COMPILE_SUCCESS_COLOR}compiled successfully!${RESET_COLOR} ${timestamp}`
32
+ );
33
+ }
34
+ return {
35
+ code: result.code,
36
+ map: result.map
37
+ };
38
+ } catch (error) {
39
+ failedFiles.add(id);
40
+ const lines = code.split("\n");
41
+ const errorLine = error.location?.line || 1;
42
+ const errorColumn = error.location?.column || 0;
43
+ const start = Math.max(0, errorLine - 4);
44
+ const end = Math.min(lines.length, errorLine + 3);
45
+ const codeFrame = lines.slice(start, end).map((line, i) => {
46
+ const lineNum = start + i + 1;
47
+ const isErrorLine = lineNum === errorLine;
48
+ const prefix = isErrorLine ? "> " : " ";
49
+ const formattedLine = `${prefix}${lineNum.toString().padStart(4)} | ${line}`;
50
+ if (isErrorLine && errorColumn > 0) {
51
+ const pointer = " ".repeat(prefix.length + 6 + errorColumn) + "^";
52
+ return `${formattedLine}
53
+ ${pointer}`;
54
+ }
55
+ return formattedLine;
56
+ }).join("\n");
57
+ const fileName = id.split("/").pop();
58
+ const errorMessage = `
59
+ ${COMPILE_ERROR_COLOR}\u2717 Fynix Transform Error${RESET_COLOR} in ${BOLD}${fileName}${RESET_COLOR}
60
+
61
+ ${error.text || error.message}
62
+
63
+ ${codeFrame}
64
+ `.trim();
65
+ console.error(errorMessage);
66
+ const viteError = Object.assign(
67
+ new Error(error.text || error.message),
68
+ {
69
+ id,
70
+ plugin: "vite-plugin-fynix",
71
+ loc: {
72
+ file: id,
73
+ line: errorLine,
74
+ column: errorColumn
75
+ },
76
+ frame: codeFrame
77
+ }
78
+ );
79
+ this.error(viteError);
80
+ }
25
81
  },
26
82
  handleHotUpdate({ file, server }) {
27
- if (file.endsWith(".ts") || file.endsWith(".js") || file.endsWith(".fnx")) {
83
+ if (/\.(js|fnx)$/.test(file) && !/node_modules/.test(file)) {
84
+ server.ws.send({
85
+ type: "custom",
86
+ event: "fynix:clear-overlay"
87
+ });
28
88
  server.ws.send({ type: "full-reload" });
29
89
  return [];
30
90
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../plugins/vite-plugin-res.js"],
4
- "sourcesContent": ["\r\nimport { transform } from \"esbuild\";\r\nexport function fynix() {\r\n return {\r\n name: \"vite-plugin-res\",\r\n enforce: \"pre\",\r\n\r\n async transform(code, id) {\r\n if (!id.includes(\"/src/\")) return null;\r\n if (!id.endsWith(\".ts\") && !id.endsWith(\".js\") && !id.endsWith(\".fnx\")) return null;\r\n this.addWatchFile(id);\r\n\r\n const result = await transform(code, {\r\n loader: \"jsx\",\r\n jsxFactory: \"Fynix\",\r\n jsxFragment: \"Fynix.Fragment\",\r\n sourcemap: true,\r\n sourcefile: id,\r\n });\r\n\r\n return {\r\n code: result.code,\r\n map: result.map,\r\n };\r\n },\r\n\r\n handleHotUpdate({ file, server }) {\r\n if (file.endsWith(\".ts\") || file.endsWith(\".js\") || file.endsWith(\".fnx\")) {\r\n server.ws.send({ type: \"full-reload\" });\r\n return [];\r\n }\r\n },\r\n };\r\n}\r\n"],
5
- "mappings": ";;AACA,SAAS,iBAAiB;AACnB,SAAS,QAAQ;AACtB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,MAAM,UAAU,MAAM,IAAI;AACxB,UAAI,CAAC,GAAG,SAAS,OAAO;AAAG,eAAO;AAClC,UAAI,CAAC,GAAG,SAAS,KAAK,KAAK,CAAC,GAAG,SAAS,KAAK,KAAK,CAAC,GAAG,SAAS,MAAM;AAAG,eAAO;AAC/E,WAAK,aAAa,EAAE;AAEpB,YAAM,SAAS,MAAM,UAAU,MAAM;AAAA,QACnC,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,aAAa;AAAA,QACb,WAAW;AAAA,QACX,YAAY;AAAA,MACd,CAAC;AAED,aAAO;AAAA,QACL,MAAM,OAAO;AAAA,QACb,KAAK,OAAO;AAAA,MACd;AAAA,IACF;AAAA,IAEA,gBAAgB,EAAE,MAAM,OAAO,GAAG;AAChC,UAAI,KAAK,SAAS,KAAK,KAAK,KAAK,SAAS,KAAK,KAAK,KAAK,SAAS,MAAM,GAAG;AACzE,eAAO,GAAG,KAAK,EAAE,MAAM,cAAc,CAAC;AACtC,eAAO,CAAC;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACF;AA/BgB;",
4
+ "sourcesContent": ["/**\r\n * @fileoverview Vite plugin for Fynix JSX transformation.\r\n * Transforms JSX syntax to Fynix function calls using esbuild.\r\n * Integrates with Fynix's error overlay system.\r\n */\r\n\r\nimport { transform } from \"esbuild\";\r\n\r\n/**\r\n * Vite plugin for transforming Fynix JSX files.\r\n * Automatically transforms .js and .fnx files.\r\n *\r\n * @returns {Object} Vite plugin object\r\n *\r\n * @example\r\n * // vite.config.js\r\n * import { defineConfig } from 'vite';\r\n * import { fynix } from '@fynixorg/ui/plugins/vite-plugin-fynix';\r\n *\r\n * export default defineConfig({\r\n * plugins: [fynix()]\r\n * });\r\n */\r\nexport function fynix() {\r\n const failedFiles = new Set();\r\n const COMPILE_SUCCESS_COLOR = \"\\x1b[32m\"; // Green\r\n const COMPILE_ERROR_COLOR = \"\\x1b[31m\"; // Red\r\n const RESET_COLOR = \"\\x1b[0m\";\r\n const BOLD = \"\\x1b[1m\";\r\n\r\n return {\r\n name: \"vite-plugin-fynix\",\r\n enforce: \"pre\",\r\n\r\n async transform(code, id) {\r\n // Only transform .js and .fnx files, exclude node_modules\r\n if (!/\\.(js|fnx)$/.test(id) || /node_modules/.test(id)) {\r\n return null;\r\n }\r\n\r\n try {\r\n const result = await transform(code, {\r\n loader: \"tsx\",\r\n jsxFactory: \"Fynix\",\r\n jsxFragment: \"Fynix.Fragment\",\r\n sourcemap: true,\r\n sourcefile: id,\r\n target: \"es2020\",\r\n });\r\n\r\n // Check if this file previously failed\r\n if (failedFiles.has(id)) {\r\n failedFiles.delete(id);\r\n const fileName = id.split(\"/\").pop();\r\n const timestamp = new Date().toLocaleTimeString();\r\n\r\n console.log(\r\n `${COMPILE_SUCCESS_COLOR}\u2713${RESET_COLOR} ` +\r\n `${BOLD}${fileName}${RESET_COLOR} ` +\r\n `${COMPILE_SUCCESS_COLOR}compiled successfully!${RESET_COLOR} ` +\r\n `${timestamp}`,\r\n );\r\n }\r\n\r\n return {\r\n code: result.code,\r\n map: result.map,\r\n };\r\n } catch (error) {\r\n // Mark this file as failed\r\n failedFiles.add(id);\r\n\r\n // Create a detailed error with code frame\r\n const lines = code.split(\"\\n\");\r\n const errorLine = error.location?.line || 1;\r\n const errorColumn = error.location?.column || 0;\r\n\r\n // Show 3 lines before and after the error\r\n const start = Math.max(0, errorLine - 4);\r\n const end = Math.min(lines.length, errorLine + 3);\r\n\r\n const codeFrame = lines\r\n .slice(start, end)\r\n .map((line, i) => {\r\n const lineNum = start + i + 1;\r\n const isErrorLine = lineNum === errorLine;\r\n const prefix = isErrorLine ? \"> \" : \" \";\r\n const formattedLine = `${prefix}${lineNum.toString().padStart(4)} | ${line}`;\r\n\r\n if (isErrorLine && errorColumn > 0) {\r\n const pointer = \" \".repeat(prefix.length + 6 + errorColumn) + \"^\";\r\n return `${formattedLine}\\n${pointer}`;\r\n }\r\n return formattedLine;\r\n })\r\n .join(\"\\n\");\r\n\r\n const fileName = id.split(\"/\").pop();\r\n const errorMessage = `\r\n${COMPILE_ERROR_COLOR}\u2717 Fynix Transform Error${RESET_COLOR} in ${BOLD}${fileName}${RESET_COLOR}\r\n\r\n${error.text || error.message}\r\n\r\n${codeFrame}\r\n `.trim();\r\n\r\n // Log to terminal\r\n console.error(errorMessage);\r\n\r\n // Create error object for Vite's error overlay\r\n const viteError = Object.assign(\r\n new Error(error.text || error.message),\r\n {\r\n id: id,\r\n plugin: \"vite-plugin-fynix\",\r\n loc: {\r\n file: id,\r\n line: errorLine,\r\n column: errorColumn,\r\n },\r\n frame: codeFrame,\r\n },\r\n );\r\n\r\n this.error(viteError);\r\n }\r\n },\r\n\r\n handleHotUpdate({ file, server }) {\r\n // Only reload for .js and .fnx files, exclude node_modules\r\n if (/\\.(js|fnx)$/.test(file) && !/node_modules/.test(file)) {\r\n // Clear Fynix error overlay on HMR\r\n server.ws.send({\r\n type: \"custom\",\r\n event: \"fynix:clear-overlay\",\r\n });\r\n\r\n // Full reload for Fynix components\r\n server.ws.send({ type: \"full-reload\" });\r\n return [];\r\n }\r\n },\r\n };\r\n}\r\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,5 +1,9 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ function isExternal(url) {
4
+ return /^https?:\/\//.test(url);
5
+ }
6
+ __name(isExternal, "isExternal");
3
7
  import { mount } from "../runtime.js";
4
8
  const MAX_CACHE_SIZE = 50;
5
9
  const PROPS_NAMESPACE = "__fynixLinkProps__";
@@ -21,7 +25,10 @@ function isValidURL(url) {
21
25
  return false;
22
26
  }
23
27
  if (!ALLOWED_PROTOCOLS.includes(parsed.protocol)) {
24
- console.warn("[Router] Security: Dangerous protocol blocked:", parsed.protocol);
28
+ console.warn(
29
+ "[Router] Security: Dangerous protocol blocked:",
30
+ parsed.protocol
31
+ );
25
32
  return false;
26
33
  }
27
34
  return true;
@@ -55,7 +62,9 @@ function sanitizePath(path) {
55
62
  __name(sanitizePath, "sanitizePath");
56
63
  function tryGlobPaths() {
57
64
  try {
58
- const modules = import.meta.glob("/src/**/*.{ts,js,jsx,fnx}", { eager: true });
65
+ const modules = import.meta.glob("/src/**/*.{ts,js,jsx,fnx}", {
66
+ eager: true
67
+ });
59
68
  return modules || {};
60
69
  } catch (error) {
61
70
  console.error("[Router] Failed to load modules:", error);
@@ -112,7 +121,9 @@ __name(generateCacheKey, "generateCacheKey");
112
121
  function createFynix() {
113
122
  const isDevMode = import.meta.hot !== void 0;
114
123
  if (routerInstance && isRouterInitialized && !isDevMode) {
115
- console.warn("[Router] Router already initialized, returning existing instance");
124
+ console.warn(
125
+ "[Router] Router already initialized, returning existing instance"
126
+ );
116
127
  return routerInstance;
117
128
  }
118
129
  if (isDevMode && routerInstance) {
@@ -349,13 +360,18 @@ function createFynix() {
349
360
  console.warn("[Router] Missing href attribute");
350
361
  return;
351
362
  }
363
+ if (isExternal(href)) {
364
+ return;
365
+ }
352
366
  const fullUrl = new URL(link.href, window.location.origin).href;
353
367
  if (!isValidURL(fullUrl)) {
354
368
  console.warn("[Router] Invalid link href");
355
369
  return;
356
370
  }
357
371
  e.preventDefault();
358
- const path = normalizePath(new URL(link.href, window.location.origin).pathname);
372
+ const path = normalizePath(
373
+ new URL(link.href, window.location.origin).pathname
374
+ );
359
375
  if (path === currentPath)
360
376
  return;
361
377
  let props = {};
@@ -386,10 +402,18 @@ function createFynix() {
386
402
  }, "clickHandler");
387
403
  if (listenerCount < MAX_LISTENERS && !isRouterInitialized) {
388
404
  document.addEventListener("click", clickHandler);
389
- listeners.push({ element: document, event: "click", handler: clickHandler });
405
+ listeners.push({
406
+ element: document,
407
+ event: "click",
408
+ handler: clickHandler
409
+ });
390
410
  listenerCount++;
391
411
  window.addEventListener("popstate", renderRoute);
392
- listeners.push({ element: window, event: "popstate", handler: renderRoute });
412
+ listeners.push({
413
+ element: window,
414
+ event: "popstate",
415
+ handler: renderRoute
416
+ });
393
417
  listenerCount++;
394
418
  }
395
419
  function cleanup() {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../router/router.js"],
4
- "sourcesContent": ["/**\r\n * Fynix File-Based Router - PRODUCTION FIXED VERSION\r\n * All Security & Memory Leak Issues Fixed\r\n */\r\n\r\nimport { mount } from \"../runtime.js\";\r\n\r\nconst MAX_CACHE_SIZE = 50;\r\nconst PROPS_NAMESPACE = '__fynixLinkProps__';\r\nconst MAX_LISTENERS = 100;\r\nconst ALLOWED_PROTOCOLS = ['http:', 'https:', ''];\r\n\r\n// FIX 1: Singleton pattern to prevent multiple router instances\r\nlet routerInstance = null;\r\nlet isRouterInitialized = false;\r\n\r\n/**\r\n * Security: Improved HTML escaping to prevent XSS\r\n */\r\nfunction escapeHTML(str) {\r\n if (typeof str !== 'string') return '';\r\n return str\r\n .replace(/&/g, '&amp;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;')\r\n .replace(/\"/g, '&quot;')\r\n .replace(/'/g, '&#039;')\r\n .replace(/`/g, '&#96;')\r\n .replace(/\\//g, '&#x2F;');\r\n}\r\n\r\n/**\r\n * Security: Validate URL to prevent open redirect\r\n */\r\nfunction isValidURL(url) {\r\n try {\r\n const parsed = new URL(url, window.location.origin);\r\n \r\n if (parsed.origin !== window.location.origin) {\r\n console.warn('[Router] Security: Cross-origin navigation blocked');\r\n return false;\r\n }\r\n \r\n if (!ALLOWED_PROTOCOLS.includes(parsed.protocol)) {\r\n console.warn('[Router] Security: Dangerous protocol blocked:', parsed.protocol);\r\n return false;\r\n }\r\n \r\n return true;\r\n } catch (e) {\r\n console.warn('[Router] Security: Invalid URL blocked');\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Security: Sanitize path to prevent directory traversal\r\n */\r\nfunction sanitizePath(path) {\r\n if (typeof path !== 'string') return '/';\r\n \r\n // Decode URL encoding first to catch encoded traversal attempts like %2e%2e\r\n try {\r\n path = decodeURIComponent(path);\r\n } catch (e) {\r\n // Invalid encoding, reject\r\n console.warn('[Router] Invalid URL encoding in path');\r\n return '/';\r\n }\r\n \r\n path = path.replace(/\\0/g, '');\r\n path = path.replace(/\\\\/g, '/');\r\n path = path.replace(/\\/+/g, '/');\r\n path = path.split('/').filter(part => part !== '..' && part !== '.').join('/');\r\n \r\n if (!path.startsWith('/')) {\r\n path = '/' + path;\r\n }\r\n \r\n if (path.length > 1 && path.endsWith('/')) {\r\n path = path.slice(0, -1);\r\n }\r\n \r\n return path || '/';\r\n}\r\n\r\n/**\r\n * Helper: Try multiple possible glob paths for file-based routing\r\n */\r\nfunction tryGlobPaths() {\r\n try {\r\n // @ts-ignore - Vite glob API\r\n const modules = import.meta.glob(\"/src/**/*.{ts,js,jsx,fnx}\", { eager: true });\r\n return modules || {};\r\n } catch (error) {\r\n console.error('[Router] Failed to load modules:', error);\r\n return {};\r\n }\r\n}\r\n\r\n/**\r\n * Convert file path to route path\r\n */\r\nfunction filePathToRoute(filePath) {\r\n let route = filePath\r\n .replace(/^.*\\/src/, \"\")\r\n .replace(/\\.(js|jsx|fnx)$/, \"\")\r\n .replace(/\\/view$/, \"\")\r\n .replace(/\\/$/, \"\");\r\n\r\n if (!route) route = \"/\";\r\n route = route.replace(/\\[([^\\]]+)\\]/g, \":$1\");\r\n return route;\r\n}\r\n\r\n/**\r\n * Match a dynamic route pattern\r\n */\r\nfunction matchDynamicRoute(path, dynamicRoutes) {\r\n for (const route of dynamicRoutes) {\r\n const match = path.match(route.regex);\r\n if (match) {\r\n const params = {};\r\n route.params.forEach((param, i) => {\r\n // FIX: Don't decode again - already decoded in sanitizePath\r\n // Just escape the matched value\r\n params[param] = escapeHTML(match[i + 1]);\r\n });\r\n return { component: route.component, params };\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Deserialize plain props\r\n */\r\nfunction deserializeProps(props) {\r\n if (!props || typeof props !== 'object') return {};\r\n \r\n const deserialized = {};\r\n for (const [key, value] of Object.entries(props)) {\r\n if (typeof key !== 'string' || key.startsWith('__')) {\r\n continue;\r\n }\r\n deserialized[key] = value;\r\n }\r\n return deserialized;\r\n}\r\n\r\n/**\r\n * Normalize path\r\n */\r\nfunction normalizePath(path) {\r\n return sanitizePath(path);\r\n}\r\n\r\n/**\r\n * FIX 2: Generate unique cache keys using crypto API when available\r\n */\r\nfunction generateCacheKey() {\r\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\r\n return crypto.randomUUID();\r\n }\r\n // Fallback with better uniqueness\r\n return `${Date.now()}-${Math.random().toString(36).slice(2)}-${Math.random().toString(36).slice(2)}`;\r\n}\r\n\r\n/**\r\n * @typedef {Object} FynixRouter\r\n * @property {function(string=): void} mountRouter - Mount router to DOM element\r\n * @property {function(string, Object=): void} navigate - Navigate to path with props\r\n * @property {function(string, Object=): void} replace - Replace current path\r\n * @property {function(): void} back - Navigate back\r\n * @property {function(): void} cleanup - Cleanup router instance\r\n * @property {Object} routes - Static routes map\r\n * @property {Array} dynamicRoutes - Dynamic routes array\r\n */\r\n\r\n/**\r\n * Fynix Router Factory\r\n * @returns {FynixRouter}\r\n */\r\nexport default function createFynix() {\r\n // FIX 3: Singleton pattern - return existing instance if already initialized\r\n // Skip singleton check in dev mode (HMR) to allow hot reloading\r\n const isDevMode = import.meta.hot !== undefined;\r\n \r\n if (routerInstance && isRouterInitialized && !isDevMode) {\r\n console.warn('[Router] Router already initialized, returning existing instance');\r\n return routerInstance;\r\n }\r\n \r\n // In dev mode with HMR, cleanup old instance before creating new one\r\n if (isDevMode && routerInstance) {\r\n console.log('[Router] HMR: Cleaning up old router instance');\r\n routerInstance.cleanup();\r\n routerInstance = null;\r\n isRouterInitialized = false;\r\n }\r\n\r\n let rootSelector = \"#app-root\";\r\n let currentPath = null;\r\n let isDestroyed = false;\r\n let listenerCount = 0;\r\n\r\n const listeners = [];\r\n\r\n if (!window[PROPS_NAMESPACE]) {\r\n window[PROPS_NAMESPACE] = {};\r\n }\r\n\r\n // Clear old cache in dev mode to prevent memory buildup\r\n if (isDevMode && window.__fynixPropsCache) {\r\n window.__fynixPropsCache.clear();\r\n }\r\n\r\n // @ts-ignore - Custom cache property\r\n const __fynixPropsCache = window.__fynixPropsCache || new Map();\r\n // @ts-ignore\r\n window.__fynixPropsCache = __fynixPropsCache;\r\n\r\n const modules = tryGlobPaths();\r\n const routes = {};\r\n const dynamicRoutes = [];\r\n\r\n for (const [filePath, mod] of Object.entries(modules)) {\r\n const routePath = filePathToRoute(filePath);\r\n const component = mod.default || mod[Object.keys(mod)[0]] || Object.values(mod)[0];\r\n\r\n if (!component) continue;\r\n\r\n const hasDynamic = /:[^/]+/.test(routePath);\r\n if (hasDynamic) {\r\n dynamicRoutes.push({\r\n pattern: routePath,\r\n regex: new RegExp(\"^\" + routePath.replace(/:[^/]+/g, \"([^/]+)\") + \"$\"),\r\n component,\r\n params: [...routePath.matchAll(/:([^/]+)/g)].map((m) => m[1]),\r\n });\r\n } else {\r\n routes[routePath] = component;\r\n }\r\n }\r\n\r\n /**\r\n * Add cache management with LRU\r\n */\r\n function addToCache(key, value) {\r\n if (__fynixPropsCache.size >= MAX_CACHE_SIZE) {\r\n const firstKey = __fynixPropsCache.keys().next().value;\r\n const evicted = __fynixPropsCache.get(firstKey);\r\n \r\n if (evicted && typeof evicted === 'object') {\r\n Object.values(evicted).forEach(val => {\r\n if (val && typeof val === 'object' && val.cleanup) {\r\n try { val.cleanup(); } catch (e) {}\r\n }\r\n });\r\n }\r\n \r\n __fynixPropsCache.delete(firstKey);\r\n }\r\n __fynixPropsCache.set(key, value);\r\n }\r\n\r\n const MANAGED_META = [\r\n { key: \"description\", name: \"description\" },\r\n { key: \"keywords\", name: \"keywords\" },\r\n { key: \"twitterCard\", name: \"twitter:card\" },\r\n { key: \"ogTitle\", property: \"og:title\" },\r\n { key: \"ogDescription\", property: \"og:description\" },\r\n { key: \"ogImage\", property: \"og:image\" },\r\n ];\r\n\r\n /**\r\n * Update document meta tags for SEO with XSS prevention\r\n * @param {Object} meta - Meta object\r\n */\r\n function updateMetaTags(meta = {}) {\r\n if (!meta || typeof meta !== 'object') return;\r\n\r\n if (meta.title && typeof meta.title === 'string') {\r\n document.title = escapeHTML(meta.title);\r\n }\r\n\r\n MANAGED_META.forEach(def => {\r\n const value = meta[def.key];\r\n\r\n const selector = def.name\r\n ? `meta[name=\"${def.name}\"]`\r\n : `meta[property=\"${def.property}\"]`;\r\n\r\n let el = document.querySelector(selector);\r\n\r\n if (value == null) {\r\n if (el) el.remove();\r\n return;\r\n }\r\n\r\n if (typeof value !== 'string') return;\r\n\r\n if (!el) {\r\n el = document.createElement(\"meta\");\r\n if (def.name) el.setAttribute(\"name\", def.name);\r\n if (def.property) el.setAttribute(\"property\", def.property);\r\n document.head.appendChild(el);\r\n }\r\n\r\n el.setAttribute(\"content\", escapeHTML(value));\r\n });\r\n }\r\n\r\n // FIX 4: Debounce renderRoute to prevent race conditions\r\n let renderTimeout = null;\r\n const RENDER_DEBOUNCE = 10; // ms\r\n\r\n /**\r\n * Core route rendering function\r\n */\r\n function renderRoute() {\r\n if (isDestroyed) return;\r\n\r\n // FIX 5: Debounce to prevent race conditions\r\n if (renderTimeout) {\r\n clearTimeout(renderTimeout);\r\n }\r\n\r\n renderTimeout = setTimeout(() => {\r\n _renderRouteImmediate();\r\n renderTimeout = null;\r\n }, RENDER_DEBOUNCE);\r\n }\r\n\r\n function _renderRouteImmediate() {\r\n if (isDestroyed) return;\r\n\r\n const path = normalizePath(window.location.pathname);\r\n let Page = routes[path];\r\n let params = {};\r\n let routeProps = {};\r\n\r\n if (!Page) {\r\n const match = matchDynamicRoute(path, dynamicRoutes);\r\n if (match) {\r\n Page = match.component;\r\n params = match.params;\r\n }\r\n }\r\n\r\n const root = document.querySelector(rootSelector);\r\n if (!root) {\r\n console.error(\"[Router] Root element not found:\", rootSelector);\r\n return;\r\n }\r\n\r\n if (!Page) {\r\n root.innerHTML = `<h2>404 Not Found</h2><p>Path: ${escapeHTML(path)}</p>`;\r\n updateMetaTags({ title: \"404 - Page Not Found\" });\r\n return;\r\n }\r\n\r\n const state = window.history.state || {};\r\n let passedProps = {};\r\n \r\n if (state.__fynixCacheKey && __fynixPropsCache.has(state.__fynixCacheKey)) {\r\n passedProps = __fynixPropsCache.get(state.__fynixCacheKey);\r\n } else if (state.serializedProps) {\r\n passedProps = deserializeProps(state.serializedProps);\r\n }\r\n\r\n if (Page.props) {\r\n routeProps = typeof Page.props === \"function\" ? Page.props() : Page.props;\r\n }\r\n\r\n if (Page.meta) {\r\n const meta = typeof Page.meta === \"function\" ? Page.meta(params) : Page.meta;\r\n updateMetaTags(meta);\r\n }\r\n\r\n // @ts-ignore\r\n window.__lastRouteProps = {\r\n ...routeProps,\r\n ...passedProps,\r\n params,\r\n };\r\n\r\n try {\r\n mount(Page, rootSelector, false, window.__lastRouteProps);\r\n } catch (err) {\r\n console.error(\"[Router] Mount failed:\", err);\r\n root.innerHTML = `<pre style=\"color:red;\">Mount Error occurred</pre>`;\r\n }\r\n\r\n currentPath = path;\r\n }\r\n\r\n /**\r\n * SPA Navigation Helpers\r\n */\r\n function navigate(path, props = {}) {\r\n if (isDestroyed) return;\r\n \r\n path = normalizePath(path);\r\n \r\n if (!isValidURL(window.location.origin + path)) {\r\n console.error('[Router] Invalid navigation URL');\r\n return;\r\n }\r\n \r\n if (path === currentPath) return;\r\n \r\n const cacheKey = generateCacheKey();\r\n addToCache(cacheKey, props);\r\n \r\n try {\r\n window.history.pushState({ __fynixCacheKey: cacheKey }, \"\", path);\r\n renderRoute();\r\n } catch (err) {\r\n console.error('[Router] Navigation failed:', err);\r\n }\r\n }\r\n\r\n function replace(path, props = {}) {\r\n if (isDestroyed) return;\r\n \r\n path = normalizePath(path);\r\n \r\n if (!isValidURL(window.location.origin + path)) {\r\n console.error('[Router] Invalid replace URL');\r\n return;\r\n }\r\n \r\n const cacheKey = generateCacheKey();\r\n addToCache(cacheKey, props);\r\n \r\n try {\r\n window.history.replaceState({ __fynixCacheKey: cacheKey }, \"\", path);\r\n renderRoute();\r\n } catch (err) {\r\n console.error('[Router] Replace failed:', err);\r\n }\r\n }\r\n\r\n function back() {\r\n if (isDestroyed) return;\r\n try {\r\n window.history.back();\r\n } catch (err) {\r\n console.error('[Router] Back navigation failed:', err);\r\n }\r\n }\r\n\r\n /**\r\n * Mount the router to a DOM element\r\n */\r\n function mountRouter(selector = \"#app-root\") {\r\n if (isDestroyed) {\r\n console.error(\"[Router] Cannot mount destroyed router\");\r\n return;\r\n }\r\n \r\n if (typeof selector !== 'string' || selector.length === 0) {\r\n console.error('[Router] Invalid selector');\r\n return;\r\n }\r\n \r\n rootSelector = selector;\r\n renderRoute();\r\n isRouterInitialized = true;\r\n }\r\n\r\n /**\r\n * Link click delegation\r\n */\r\n const clickHandler = (e) => {\r\n if (isDestroyed) return;\r\n\r\n const link = e.target.closest(\"a[data-fynix-link]\");\r\n if (!link) return;\r\n\r\n const href = link.getAttribute('href');\r\n if (!href) {\r\n console.warn('[Router] Missing href attribute');\r\n return;\r\n }\r\n\r\n // FIX: Build full URL for validation (handles relative URLs)\r\n const fullUrl = new URL(link.href, window.location.origin).href;\r\n if (!isValidURL(fullUrl)) {\r\n console.warn('[Router] Invalid link href');\r\n return;\r\n }\r\n\r\n e.preventDefault();\r\n\r\n const path = normalizePath(new URL(link.href, window.location.origin).pathname);\r\n\r\n if (path === currentPath) return;\r\n\r\n let props = {};\r\n const propsKey = link.getAttribute(\"data-props-key\");\r\n \r\n if (propsKey && typeof propsKey === 'string' && !propsKey.startsWith('__')) {\r\n if (window[PROPS_NAMESPACE]?.[propsKey]) {\r\n props = window[PROPS_NAMESPACE][propsKey];\r\n }\r\n }\r\n\r\n const serializableProps = {};\r\n for (const [k, v] of Object.entries(props)) {\r\n if (typeof k !== 'string' || k.startsWith('__')) continue;\r\n serializableProps[k] = v && (v._isNixState || v._isRestState) ? v.value : v;\r\n }\r\n\r\n const cacheKey = generateCacheKey();\r\n addToCache(cacheKey, serializableProps);\r\n\r\n try {\r\n window.history.pushState(\r\n { __fynixCacheKey: cacheKey, serializedProps: serializableProps },\r\n \"\",\r\n path\r\n );\r\n renderRoute();\r\n } catch (err) {\r\n console.error('[Router] Link navigation failed:', err);\r\n }\r\n };\r\n\r\n // FIX 6: Only add listeners if not already added\r\n if (listenerCount < MAX_LISTENERS && !isRouterInitialized) {\r\n document.addEventListener(\"click\", clickHandler);\r\n listeners.push({ element: document, event: \"click\", handler: clickHandler });\r\n listenerCount++;\r\n\r\n window.addEventListener(\"popstate\", renderRoute);\r\n listeners.push({ element: window, event: \"popstate\", handler: renderRoute });\r\n listenerCount++;\r\n }\r\n\r\n /**\r\n * Cleanup function\r\n */\r\n function cleanup() {\r\n // FIX: Clear timeout FIRST to prevent pending renders\r\n if (renderTimeout) {\r\n clearTimeout(renderTimeout);\r\n renderTimeout = null;\r\n }\r\n\r\n // THEN mark as destroyed\r\n isDestroyed = true;\r\n\r\n // Remove all event listeners\r\n listeners.forEach(({ element, event, handler }) => {\r\n try {\r\n element.removeEventListener(event, handler);\r\n } catch (e) {\r\n console.error('[Router] Cleanup error:', e);\r\n }\r\n });\r\n listeners.length = 0;\r\n listenerCount = 0;\r\n\r\n // Clean up all cached props\r\n __fynixPropsCache.forEach(props => {\r\n if (props && typeof props === 'object') {\r\n Object.values(props).forEach(val => {\r\n if (val && typeof val === 'object' && val.cleanup) {\r\n try { val.cleanup(); } catch (e) {}\r\n }\r\n });\r\n }\r\n });\r\n __fynixPropsCache.clear();\r\n\r\n // Clean up global namespace\r\n if (window[PROPS_NAMESPACE]) {\r\n Object.keys(window[PROPS_NAMESPACE]).forEach(key => {\r\n delete window[PROPS_NAMESPACE][key];\r\n });\r\n delete window[PROPS_NAMESPACE];\r\n }\r\n\r\n // Clear last route props\r\n // @ts-ignore\r\n if (window.__lastRouteProps) {\r\n // @ts-ignore\r\n delete window.__lastRouteProps;\r\n }\r\n\r\n // Reset singleton flags at the VERY end\r\n isRouterInitialized = false;\r\n routerInstance = null;\r\n \r\n console.log(\"[Router] Cleanup complete\");\r\n }\r\n\r\n // @ts-ignore - Vite HMR API\r\n if (import.meta.hot) {\r\n // @ts-ignore\r\n import.meta.hot.accept(() => {\r\n console.log(\"[Router] HMR detected, re-rendering route...\");\r\n renderRoute();\r\n });\r\n\r\n // @ts-ignore\r\n import.meta.hot.dispose(() => {\r\n console.log(\"[Router] HMR dispose, cleaning up...\");\r\n cleanup();\r\n // Reset singleton flags for HMR\r\n routerInstance = null;\r\n isRouterInitialized = false;\r\n });\r\n }\r\n\r\n const router = {\r\n mountRouter,\r\n navigate,\r\n replace,\r\n back,\r\n cleanup,\r\n routes,\r\n dynamicRoutes,\r\n };\r\n\r\n routerInstance = router;\r\n return router;\r\n}\r\n\r\n/**\r\n * Helper: Set props for links\r\n */\r\nexport function setLinkProps(key, props) {\r\n if (typeof key !== 'string' || key.startsWith('__')) {\r\n console.error('[Router] Invalid props key');\r\n return;\r\n }\r\n \r\n if (!props || typeof props !== 'object') {\r\n console.error('[Router] Invalid props object');\r\n return;\r\n }\r\n \r\n if (!window[PROPS_NAMESPACE]) {\r\n window[PROPS_NAMESPACE] = {};\r\n }\r\n \r\n if (Object.keys(window[PROPS_NAMESPACE]).length >= MAX_CACHE_SIZE) {\r\n console.warn('[Router] Props storage limit reached');\r\n return;\r\n }\r\n \r\n window[PROPS_NAMESPACE][key] = props;\r\n}\r\n\r\n/**\r\n * Helper: Clear link props\r\n */\r\nexport function clearLinkProps(key) {\r\n if (typeof key !== 'string') return;\r\n \r\n if (window[PROPS_NAMESPACE]?.[key]) {\r\n const props = window[PROPS_NAMESPACE][key];\r\n if (props && typeof props === 'object') {\r\n Object.values(props).forEach(val => {\r\n if (val && typeof val === 'object' && val.cleanup) {\r\n try { val.cleanup(); } catch (e) {}\r\n }\r\n });\r\n }\r\n delete window[PROPS_NAMESPACE][key];\r\n }\r\n}\r\n\r\n// Named export for better IDE support\r\nexport { createFynix };"],
5
- "mappings": "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",
4
+ "sourcesContent": ["// Helper: Detect external URLs\r\nfunction isExternal(url) {\r\n return /^https?:\\/\\//.test(url);\r\n}\r\n/**\r\n * Fynix File-Based Router\r\n * All Security & Memory Leak Issues Fixed\r\n */\r\n\r\nimport { mount } from \"../runtime.js\";\r\n\r\nconst MAX_CACHE_SIZE = 50;\r\nconst PROPS_NAMESPACE = \"__fynixLinkProps__\";\r\nconst MAX_LISTENERS = 100;\r\nconst ALLOWED_PROTOCOLS = [\"http:\", \"https:\", \"\"];\r\n\r\n// FIX 1: Singleton pattern to prevent multiple router instances\r\nlet routerInstance = null;\r\nlet isRouterInitialized = false;\r\n\r\n/**\r\n * Security: Improved HTML escaping to prevent XSS\r\n */\r\nfunction escapeHTML(str) {\r\n if (typeof str !== \"string\") return \"\";\r\n return str\r\n .replace(/&/g, \"&amp;\")\r\n .replace(/</g, \"&lt;\")\r\n .replace(/>/g, \"&gt;\")\r\n .replace(/\"/g, \"&quot;\")\r\n .replace(/'/g, \"&#039;\")\r\n .replace(/`/g, \"&#96;\")\r\n .replace(/\\//g, \"&#x2F;\");\r\n}\r\n\r\n/**\r\n * Security: Validate URL to prevent open redirect\r\n */\r\nfunction isValidURL(url) {\r\n try {\r\n const parsed = new URL(url, window.location.origin);\r\n\r\n if (parsed.origin !== window.location.origin) {\r\n console.warn(\"[Router] Security: Cross-origin navigation blocked\");\r\n return false;\r\n }\r\n\r\n if (!ALLOWED_PROTOCOLS.includes(parsed.protocol)) {\r\n console.warn(\r\n \"[Router] Security: Dangerous protocol blocked:\",\r\n parsed.protocol\r\n );\r\n return false;\r\n }\r\n\r\n return true;\r\n } catch (e) {\r\n console.warn(\"[Router] Security: Invalid URL blocked\");\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Security: Sanitize path to prevent directory traversal\r\n */\r\nfunction sanitizePath(path) {\r\n if (typeof path !== \"string\") return \"/\";\r\n\r\n // Decode URL encoding first to catch encoded traversal attempts like %2e%2e\r\n try {\r\n path = decodeURIComponent(path);\r\n } catch (e) {\r\n // Invalid encoding, reject\r\n console.warn(\"[Router] Invalid URL encoding in path\");\r\n return \"/\";\r\n }\r\n\r\n path = path.replace(/\\0/g, \"\");\r\n path = path.replace(/\\\\/g, \"/\");\r\n path = path.replace(/\\/+/g, \"/\");\r\n path = path\r\n .split(\"/\")\r\n .filter((part) => part !== \"..\" && part !== \".\")\r\n .join(\"/\");\r\n\r\n if (!path.startsWith(\"/\")) {\r\n path = \"/\" + path;\r\n }\r\n\r\n if (path.length > 1 && path.endsWith(\"/\")) {\r\n path = path.slice(0, -1);\r\n }\r\n\r\n return path || \"/\";\r\n}\r\n\r\n/**\r\n * Helper: Try multiple possible glob paths for file-based routing\r\n */\r\nfunction tryGlobPaths() {\r\n try {\r\n // @ts-ignore - Vite glob API\r\n const modules = import.meta.glob(\"/src/**/*.{ts,js,jsx,fnx}\", {\r\n eager: true,\r\n });\r\n return modules || {};\r\n } catch (error) {\r\n console.error(\"[Router] Failed to load modules:\", error);\r\n return {};\r\n }\r\n}\r\n\r\n/**\r\n * Convert file path to route path\r\n */\r\nfunction filePathToRoute(filePath) {\r\n let route = filePath\r\n .replace(/^.*\\/src/, \"\")\r\n .replace(/\\.(js|jsx|fnx)$/, \"\")\r\n .replace(/\\/view$/, \"\")\r\n .replace(/\\/$/, \"\");\r\n\r\n if (!route) route = \"/\";\r\n route = route.replace(/\\[([^\\]]+)\\]/g, \":$1\");\r\n return route;\r\n}\r\n\r\n/**\r\n * Match a dynamic route pattern\r\n */\r\nfunction matchDynamicRoute(path, dynamicRoutes) {\r\n for (const route of dynamicRoutes) {\r\n const match = path.match(route.regex);\r\n if (match) {\r\n const params = {};\r\n route.params.forEach((param, i) => {\r\n // FIX: Don't decode again - already decoded in sanitizePath\r\n // Just escape the matched value\r\n params[param] = escapeHTML(match[i + 1]);\r\n });\r\n return { component: route.component, params };\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Deserialize plain props\r\n */\r\nfunction deserializeProps(props) {\r\n if (!props || typeof props !== \"object\") return {};\r\n\r\n const deserialized = {};\r\n for (const [key, value] of Object.entries(props)) {\r\n if (typeof key !== \"string\" || key.startsWith(\"__\")) {\r\n continue;\r\n }\r\n deserialized[key] = value;\r\n }\r\n return deserialized;\r\n}\r\n\r\n/**\r\n * Normalize path\r\n */\r\nfunction normalizePath(path) {\r\n return sanitizePath(path);\r\n}\r\n\r\n/**\r\n * FIX 2: Generate unique cache keys using crypto API when available\r\n */\r\nfunction generateCacheKey() {\r\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\r\n return crypto.randomUUID();\r\n }\r\n // Fallback with better uniqueness\r\n return `${Date.now()}-${Math.random().toString(36).slice(2)}-${Math.random()\r\n .toString(36)\r\n .slice(2)}`;\r\n}\r\n\r\n/**\r\n * @typedef {Object} FynixRouter\r\n * @property {function(string=): void} mountRouter - Mount router to DOM element\r\n * @property {function(string, Object=): void} navigate - Navigate to path with props\r\n * @property {function(string, Object=): void} replace - Replace current path\r\n * @property {function(): void} back - Navigate back\r\n * @property {function(): void} cleanup - Cleanup router instance\r\n * @property {Object} routes - Static routes map\r\n * @property {Array} dynamicRoutes - Dynamic routes array\r\n */\r\n\r\n/**\r\n * Fynix Router Factory\r\n * @returns {FynixRouter}\r\n */\r\nexport default function createFynix() {\r\n // FIX 3: Singleton pattern - return existing instance if already initialized\r\n // Skip singleton check in dev mode (HMR) to allow hot reloading\r\n const isDevMode = import.meta.hot !== undefined;\r\n\r\n if (routerInstance && isRouterInitialized && !isDevMode) {\r\n console.warn(\r\n \"[Router] Router already initialized, returning existing instance\"\r\n );\r\n return routerInstance;\r\n }\r\n\r\n // In dev mode with HMR, cleanup old instance before creating new one\r\n if (isDevMode && routerInstance) {\r\n console.log(\"[Router] HMR: Cleaning up old router instance\");\r\n routerInstance.cleanup();\r\n routerInstance = null;\r\n isRouterInitialized = false;\r\n }\r\n\r\n let rootSelector = \"#app-root\";\r\n let currentPath = null;\r\n let isDestroyed = false;\r\n let listenerCount = 0;\r\n\r\n const listeners = [];\r\n\r\n if (!window[PROPS_NAMESPACE]) {\r\n window[PROPS_NAMESPACE] = {};\r\n }\r\n\r\n // Clear old cache in dev mode to prevent memory buildup\r\n if (isDevMode && window.__fynixPropsCache) {\r\n window.__fynixPropsCache.clear();\r\n }\r\n\r\n // @ts-ignore - Custom cache property\r\n const __fynixPropsCache = window.__fynixPropsCache || new Map();\r\n // @ts-ignore\r\n window.__fynixPropsCache = __fynixPropsCache;\r\n\r\n const modules = tryGlobPaths();\r\n const routes = {};\r\n const dynamicRoutes = [];\r\n\r\n for (const [filePath, mod] of Object.entries(modules)) {\r\n const routePath = filePathToRoute(filePath);\r\n const component =\r\n mod.default || mod[Object.keys(mod)[0]] || Object.values(mod)[0];\r\n\r\n if (!component) continue;\r\n\r\n const hasDynamic = /:[^/]+/.test(routePath);\r\n if (hasDynamic) {\r\n dynamicRoutes.push({\r\n pattern: routePath,\r\n regex: new RegExp(\"^\" + routePath.replace(/:[^/]+/g, \"([^/]+)\") + \"$\"),\r\n component,\r\n params: [...routePath.matchAll(/:([^/]+)/g)].map((m) => m[1]),\r\n });\r\n } else {\r\n routes[routePath] = component;\r\n }\r\n }\r\n\r\n /**\r\n * Add cache management with LRU\r\n */\r\n function addToCache(key, value) {\r\n if (__fynixPropsCache.size >= MAX_CACHE_SIZE) {\r\n const firstKey = __fynixPropsCache.keys().next().value;\r\n const evicted = __fynixPropsCache.get(firstKey);\r\n\r\n if (evicted && typeof evicted === \"object\") {\r\n Object.values(evicted).forEach((val) => {\r\n if (val && typeof val === \"object\" && val.cleanup) {\r\n try {\r\n val.cleanup();\r\n } catch (e) {}\r\n }\r\n });\r\n }\r\n\r\n __fynixPropsCache.delete(firstKey);\r\n }\r\n __fynixPropsCache.set(key, value);\r\n }\r\n\r\n const MANAGED_META = [\r\n { key: \"description\", name: \"description\" },\r\n { key: \"keywords\", name: \"keywords\" },\r\n { key: \"twitterCard\", name: \"twitter:card\" },\r\n { key: \"ogTitle\", property: \"og:title\" },\r\n { key: \"ogDescription\", property: \"og:description\" },\r\n { key: \"ogImage\", property: \"og:image\" },\r\n ];\r\n\r\n /**\r\n * Update document meta tags for SEO with XSS prevention\r\n * @param {Object} meta - Meta object\r\n */\r\n function updateMetaTags(meta = {}) {\r\n if (!meta || typeof meta !== \"object\") return;\r\n\r\n if (meta.title && typeof meta.title === \"string\") {\r\n document.title = escapeHTML(meta.title);\r\n }\r\n\r\n MANAGED_META.forEach((def) => {\r\n const value = meta[def.key];\r\n\r\n const selector = def.name\r\n ? `meta[name=\"${def.name}\"]`\r\n : `meta[property=\"${def.property}\"]`;\r\n\r\n let el = document.querySelector(selector);\r\n\r\n if (value == null) {\r\n if (el) el.remove();\r\n return;\r\n }\r\n\r\n if (typeof value !== \"string\") return;\r\n\r\n if (!el) {\r\n el = document.createElement(\"meta\");\r\n if (def.name) el.setAttribute(\"name\", def.name);\r\n if (def.property) el.setAttribute(\"property\", def.property);\r\n document.head.appendChild(el);\r\n }\r\n\r\n el.setAttribute(\"content\", escapeHTML(value));\r\n });\r\n }\r\n\r\n // FIX 4: Debounce renderRoute to prevent race conditions\r\n let renderTimeout = null;\r\n const RENDER_DEBOUNCE = 10; // ms\r\n\r\n /**\r\n * Core route rendering function\r\n */\r\n function renderRoute() {\r\n if (isDestroyed) return;\r\n\r\n // FIX 5: Debounce to prevent race conditions\r\n if (renderTimeout) {\r\n clearTimeout(renderTimeout);\r\n }\r\n\r\n renderTimeout = setTimeout(() => {\r\n _renderRouteImmediate();\r\n renderTimeout = null;\r\n }, RENDER_DEBOUNCE);\r\n }\r\n\r\n function _renderRouteImmediate() {\r\n if (isDestroyed) return;\r\n\r\n const path = normalizePath(window.location.pathname);\r\n let Page = routes[path];\r\n let params = {};\r\n let routeProps = {};\r\n\r\n if (!Page) {\r\n const match = matchDynamicRoute(path, dynamicRoutes);\r\n if (match) {\r\n Page = match.component;\r\n params = match.params;\r\n }\r\n }\r\n\r\n const root = document.querySelector(rootSelector);\r\n if (!root) {\r\n console.error(\"[Router] Root element not found:\", rootSelector);\r\n return;\r\n }\r\n\r\n if (!Page) {\r\n root.innerHTML = `<h2>404 Not Found</h2><p>Path: ${escapeHTML(path)}</p>`;\r\n updateMetaTags({ title: \"404 - Page Not Found\" });\r\n return;\r\n }\r\n\r\n const state = window.history.state || {};\r\n let passedProps = {};\r\n\r\n if (state.__fynixCacheKey && __fynixPropsCache.has(state.__fynixCacheKey)) {\r\n passedProps = __fynixPropsCache.get(state.__fynixCacheKey);\r\n } else if (state.serializedProps) {\r\n passedProps = deserializeProps(state.serializedProps);\r\n }\r\n\r\n if (Page.props) {\r\n routeProps = typeof Page.props === \"function\" ? Page.props() : Page.props;\r\n }\r\n\r\n if (Page.meta) {\r\n const meta =\r\n typeof Page.meta === \"function\" ? Page.meta(params) : Page.meta;\r\n updateMetaTags(meta);\r\n }\r\n\r\n // @ts-ignore\r\n window.__lastRouteProps = {\r\n ...routeProps,\r\n ...passedProps,\r\n params,\r\n };\r\n\r\n try {\r\n mount(Page, rootSelector, false, window.__lastRouteProps);\r\n } catch (err) {\r\n console.error(\"[Router] Mount failed:\", err);\r\n root.innerHTML = `<pre style=\"color:red;\">Mount Error occurred</pre>`;\r\n }\r\n\r\n currentPath = path;\r\n }\r\n\r\n /**\r\n * SPA Navigation Helpers\r\n */\r\n function navigate(path, props = {}) {\r\n if (isDestroyed) return;\r\n\r\n path = normalizePath(path);\r\n\r\n if (!isValidURL(window.location.origin + path)) {\r\n console.error(\"[Router] Invalid navigation URL\");\r\n return;\r\n }\r\n\r\n if (path === currentPath) return;\r\n\r\n const cacheKey = generateCacheKey();\r\n addToCache(cacheKey, props);\r\n\r\n try {\r\n window.history.pushState({ __fynixCacheKey: cacheKey }, \"\", path);\r\n renderRoute();\r\n } catch (err) {\r\n console.error(\"[Router] Navigation failed:\", err);\r\n }\r\n }\r\n\r\n function replace(path, props = {}) {\r\n if (isDestroyed) return;\r\n\r\n path = normalizePath(path);\r\n\r\n if (!isValidURL(window.location.origin + path)) {\r\n console.error(\"[Router] Invalid replace URL\");\r\n return;\r\n }\r\n\r\n const cacheKey = generateCacheKey();\r\n addToCache(cacheKey, props);\r\n\r\n try {\r\n window.history.replaceState({ __fynixCacheKey: cacheKey }, \"\", path);\r\n renderRoute();\r\n } catch (err) {\r\n console.error(\"[Router] Replace failed:\", err);\r\n }\r\n }\r\n\r\n function back() {\r\n if (isDestroyed) return;\r\n try {\r\n window.history.back();\r\n } catch (err) {\r\n console.error(\"[Router] Back navigation failed:\", err);\r\n }\r\n }\r\n\r\n /**\r\n * Mount the router to a DOM element\r\n */\r\n function mountRouter(selector = \"#app-root\") {\r\n if (isDestroyed) {\r\n console.error(\"[Router] Cannot mount destroyed router\");\r\n return;\r\n }\r\n\r\n if (typeof selector !== \"string\" || selector.length === 0) {\r\n console.error(\"[Router] Invalid selector\");\r\n return;\r\n }\r\n\r\n rootSelector = selector;\r\n renderRoute();\r\n isRouterInitialized = true;\r\n }\r\n\r\n /**\r\n * Link click delegation\r\n */\r\n const clickHandler = (e) => {\r\n if (isDestroyed) return;\r\n\r\n const link = e.target.closest(\"a[data-fynix-link]\");\r\n if (!link) return;\r\n\r\n const href = link.getAttribute(\"href\");\r\n if (!href) {\r\n console.warn(\"[Router] Missing href attribute\");\r\n return;\r\n }\r\n\r\n // Ignore external links\r\n if (isExternal(href)) {\r\n return; // Let the browser handle it\r\n }\r\n\r\n // FIX: Build full URL for validation (handles relative URLs)\r\n const fullUrl = new URL(link.href, window.location.origin).href;\r\n if (!isValidURL(fullUrl)) {\r\n console.warn(\"[Router] Invalid link href\");\r\n return;\r\n }\r\n\r\n e.preventDefault();\r\n\r\n const path = normalizePath(\r\n new URL(link.href, window.location.origin).pathname\r\n );\r\n\r\n if (path === currentPath) return;\r\n\r\n let props = {};\r\n const propsKey = link.getAttribute(\"data-props-key\");\r\n\r\n if (\r\n propsKey &&\r\n typeof propsKey === \"string\" &&\r\n !propsKey.startsWith(\"__\")\r\n ) {\r\n if (window[PROPS_NAMESPACE]?.[propsKey]) {\r\n props = window[PROPS_NAMESPACE][propsKey];\r\n }\r\n }\r\n\r\n const serializableProps = {};\r\n for (const [k, v] of Object.entries(props)) {\r\n if (typeof k !== \"string\" || k.startsWith(\"__\")) continue;\r\n serializableProps[k] =\r\n v && (v._isNixState || v._isRestState) ? v.value : v;\r\n }\r\n\r\n const cacheKey = generateCacheKey();\r\n addToCache(cacheKey, serializableProps);\r\n\r\n try {\r\n window.history.pushState(\r\n { __fynixCacheKey: cacheKey, serializedProps: serializableProps },\r\n \"\",\r\n path\r\n );\r\n renderRoute();\r\n } catch (err) {\r\n console.error(\"[Router] Link navigation failed:\", err);\r\n }\r\n };\r\n\r\n // FIX 6: Only add listeners if not already added\r\n if (listenerCount < MAX_LISTENERS && !isRouterInitialized) {\r\n document.addEventListener(\"click\", clickHandler);\r\n listeners.push({\r\n element: document,\r\n event: \"click\",\r\n handler: clickHandler,\r\n });\r\n listenerCount++;\r\n\r\n window.addEventListener(\"popstate\", renderRoute);\r\n listeners.push({\r\n element: window,\r\n event: \"popstate\",\r\n handler: renderRoute,\r\n });\r\n listenerCount++;\r\n }\r\n\r\n /**\r\n * Cleanup function\r\n */\r\n function cleanup() {\r\n // FIX: Clear timeout FIRST to prevent pending renders\r\n if (renderTimeout) {\r\n clearTimeout(renderTimeout);\r\n renderTimeout = null;\r\n }\r\n\r\n // THEN mark as destroyed\r\n isDestroyed = true;\r\n\r\n // Remove all event listeners\r\n listeners.forEach(({ element, event, handler }) => {\r\n try {\r\n element.removeEventListener(event, handler);\r\n } catch (e) {\r\n console.error(\"[Router] Cleanup error:\", e);\r\n }\r\n });\r\n listeners.length = 0;\r\n listenerCount = 0;\r\n\r\n // Clean up all cached props\r\n __fynixPropsCache.forEach((props) => {\r\n if (props && typeof props === \"object\") {\r\n Object.values(props).forEach((val) => {\r\n if (val && typeof val === \"object\" && val.cleanup) {\r\n try {\r\n val.cleanup();\r\n } catch (e) {}\r\n }\r\n });\r\n }\r\n });\r\n __fynixPropsCache.clear();\r\n\r\n // Clean up global namespace\r\n if (window[PROPS_NAMESPACE]) {\r\n Object.keys(window[PROPS_NAMESPACE]).forEach((key) => {\r\n delete window[PROPS_NAMESPACE][key];\r\n });\r\n delete window[PROPS_NAMESPACE];\r\n }\r\n\r\n // Clear last route props\r\n // @ts-ignore\r\n if (window.__lastRouteProps) {\r\n // @ts-ignore\r\n delete window.__lastRouteProps;\r\n }\r\n\r\n // Reset singleton flags at the VERY end\r\n isRouterInitialized = false;\r\n routerInstance = null;\r\n\r\n console.log(\"[Router] Cleanup complete\");\r\n }\r\n\r\n // @ts-ignore - Vite HMR API\r\n if (import.meta.hot) {\r\n // @ts-ignore\r\n import.meta.hot.accept(() => {\r\n console.log(\"[Router] HMR detected, re-rendering route...\");\r\n renderRoute();\r\n });\r\n\r\n // @ts-ignore\r\n import.meta.hot.dispose(() => {\r\n console.log(\"[Router] HMR dispose, cleaning up...\");\r\n cleanup();\r\n // Reset singleton flags for HMR\r\n routerInstance = null;\r\n isRouterInitialized = false;\r\n });\r\n }\r\n\r\n const router = {\r\n mountRouter,\r\n navigate,\r\n replace,\r\n back,\r\n cleanup,\r\n routes,\r\n dynamicRoutes,\r\n };\r\n\r\n routerInstance = router;\r\n return router;\r\n}\r\n\r\n/**\r\n * Helper: Set props for links\r\n */\r\nexport function setLinkProps(key, props) {\r\n if (typeof key !== \"string\" || key.startsWith(\"__\")) {\r\n console.error(\"[Router] Invalid props key\");\r\n return;\r\n }\r\n\r\n if (!props || typeof props !== \"object\") {\r\n console.error(\"[Router] Invalid props object\");\r\n return;\r\n }\r\n\r\n if (!window[PROPS_NAMESPACE]) {\r\n window[PROPS_NAMESPACE] = {};\r\n }\r\n\r\n if (Object.keys(window[PROPS_NAMESPACE]).length >= MAX_CACHE_SIZE) {\r\n console.warn(\"[Router] Props storage limit reached\");\r\n return;\r\n }\r\n\r\n window[PROPS_NAMESPACE][key] = props;\r\n}\r\n\r\n/**\r\n * Helper: Clear link props\r\n */\r\nexport function clearLinkProps(key) {\r\n if (typeof key !== \"string\") return;\r\n\r\n if (window[PROPS_NAMESPACE]?.[key]) {\r\n const props = window[PROPS_NAMESPACE][key];\r\n if (props && typeof props === \"object\") {\r\n Object.values(props).forEach((val) => {\r\n if (val && typeof val === \"object\" && val.cleanup) {\r\n try {\r\n val.cleanup();\r\n } catch (e) {}\r\n }\r\n });\r\n }\r\n delete window[PROPS_NAMESPACE][key];\r\n }\r\n}\r\n\r\n// Named export for better IDE support\r\nexport { createFynix };\r\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/runtime.js CHANGED
@@ -124,7 +124,8 @@ function beginComponent(vnode) {
124
124
  _subscriptions: /* @__PURE__ */ new Set(),
125
125
  _subscriptionCleanups: [],
126
126
  version: 0,
127
- rerender: null,
127
+ /** @type {undefined | (() => void)} */
128
+ rerender: void 0,
128
129
  Component: vnode.type,
129
130
  _isMounted: false,
130
131
  _isRerendering: false
@@ -146,7 +147,7 @@ function endComponent() {
146
147
  if (!ctx._subscriptions.has(state)) {
147
148
  if (!ctx.rerender) {
148
149
  let rerenderTimeout = null;
149
- ctx.rerender = () => {
150
+ ctx.rerender = /* @__PURE__ */ __name(function rerender() {
150
151
  if (ctx._isRerendering || pendingRerenders.has(ctx)) {
151
152
  return;
152
153
  }
@@ -191,12 +192,12 @@ function endComponent() {
191
192
  }
192
193
  rerenderTimeout = null;
193
194
  }, 0);
194
- };
195
+ }, "rerender");
195
196
  }
196
197
  const unsub = state.subscribe(() => {
197
198
  if (ctx.rerender && ctx._isMounted) {
198
199
  if (typeof queueMicrotask === "function")
199
- queueMicrotask(ctx.rerender);
200
+ queueMicrotask(() => ctx.rerender());
200
201
  else
201
202
  setTimeout(ctx.rerender, 0);
202
203
  }