@fynixorg/ui 1.0.4 → 1.0.6
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.
- package/dist/build.d.ts +1 -0
- package/dist/context/context.d.ts +99 -0
- package/dist/context/context.js +3 -0
- package/dist/context/context.js.map +2 -2
- package/dist/custom/Outlet.d.ts +0 -0
- package/dist/custom/button.d.ts +62 -0
- package/dist/custom/button.js +3 -0
- package/dist/custom/button.js.map +2 -2
- package/dist/custom/index.d.ts +2 -0
- package/dist/custom/index.js.map +2 -2
- package/dist/custom/path.d.ts +71 -0
- package/dist/custom/path.js +3 -0
- package/dist/custom/path.js.map +2 -2
- package/dist/error/errorOverlay.d.ts +26 -0
- package/dist/error/errorOverlay.js +4 -0
- package/dist/error/errorOverlay.js.map +2 -2
- package/dist/fynix/index.d.ts +4 -0
- package/dist/hooks/nixAsync.d.ts +13 -0
- package/dist/hooks/nixAsync.js +7 -4
- package/dist/hooks/nixAsync.js.map +1 -1
- package/dist/hooks/nixAsyncCache.d.ts +7 -0
- package/dist/hooks/nixAsyncCache.js +7 -4
- package/dist/hooks/nixAsyncCache.js.map +1 -1
- package/dist/hooks/nixAsyncDebounce.d.ts +28 -0
- package/dist/hooks/nixAsyncDebounce.js +9 -6
- package/dist/hooks/nixAsyncDebounce.js.map +1 -1
- package/dist/hooks/nixAsyncQuery.d.ts +40 -0
- package/dist/hooks/nixAsyncQuery.js +7 -4
- package/dist/hooks/nixAsyncQuery.js.map +1 -1
- package/dist/hooks/nixCallback.d.ts +30 -0
- package/dist/hooks/nixCallback.js +4 -0
- package/dist/hooks/nixCallback.js.map +1 -1
- package/dist/hooks/nixComputed.d.ts +93 -0
- package/dist/hooks/nixComputed.js +4 -0
- package/dist/hooks/nixComputed.js.map +2 -2
- package/dist/hooks/nixDebounce.d.ts +32 -0
- package/dist/hooks/nixDebounce.js +7 -4
- package/dist/hooks/nixDebounce.js.map +2 -2
- package/dist/hooks/nixEffect.d.ts +64 -0
- package/dist/hooks/nixEffect.js +6 -0
- package/dist/hooks/nixEffect.js.map +1 -1
- package/dist/hooks/nixForm.d.ts +15 -0
- package/dist/hooks/nixForm.js +11 -0
- package/dist/hooks/nixForm.js.map +1 -1
- package/dist/hooks/nixFormAsync.d.ts +20 -0
- package/dist/hooks/nixFormAsync.js +12 -0
- package/dist/hooks/nixFormAsync.js.map +1 -1
- package/dist/hooks/nixInterval.d.ts +26 -0
- package/dist/hooks/nixInterval.js +6 -3
- package/dist/hooks/nixInterval.js.map +2 -2
- package/dist/hooks/nixLazy.d.ts +19 -0
- package/dist/hooks/nixLazy.js +6 -2
- package/dist/hooks/nixLazy.js.map +1 -1
- package/dist/hooks/nixLazyAsync.d.ts +26 -0
- package/dist/hooks/nixLazyAsync.js +10 -6
- package/dist/hooks/nixLazyAsync.js.map +1 -1
- package/dist/hooks/nixLazyFormAsync.d.ts +29 -0
- package/dist/hooks/nixLazyFormAsync.js +18 -6
- package/dist/hooks/nixLazyFormAsync.js.map +1 -1
- package/dist/hooks/nixLocalStorage.d.ts +22 -0
- package/dist/hooks/nixLocalStorage.js +5 -2
- package/dist/hooks/nixLocalStorage.js.map +2 -2
- package/dist/hooks/nixMemo.d.ts +8 -0
- package/dist/hooks/nixMemo.js +3 -0
- package/dist/hooks/nixMemo.js.map +1 -1
- package/dist/hooks/nixPrevious.d.ts +18 -0
- package/dist/hooks/nixPrevious.js +3 -0
- package/dist/hooks/nixPrevious.js.map +2 -2
- package/dist/hooks/nixRef.d.ts +10 -0
- package/dist/hooks/nixRef.js +3 -0
- package/dist/hooks/nixRef.js.map +1 -1
- package/dist/hooks/nixState.d.ts +73 -0
- package/dist/hooks/nixState.js +3 -0
- package/dist/hooks/nixState.js.map +1 -1
- package/dist/hooks/nixStore.d.ts +9 -0
- package/dist/hooks/nixStore.js +3 -0
- package/dist/hooks/nixStore.js.map +1 -1
- package/dist/plugins/vite-plugin-res.d.ts +16 -0
- package/dist/plugins/vite-plugin-res.js +80 -17
- package/dist/plugins/vite-plugin-res.js.map +2 -2
- package/dist/router/router.d.ts +53 -0
- package/dist/router/router.js +55 -8
- package/dist/router/router.js.map +2 -2
- package/dist/runtime.d.ts +91 -0
- package/dist/runtime.js +23 -4
- package/dist/runtime.js.map +2 -2
- package/package.json +4 -5
- package/types/global.d.ts +33 -20
- package/router/router.d.ts +0 -21
- package/router/router.js +0 -678
- package/runtime.d.ts +0 -83
package/dist/router/router.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
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");
|
|
1
7
|
import { mount } from "../runtime.js";
|
|
2
8
|
const MAX_CACHE_SIZE = 50;
|
|
3
9
|
const PROPS_NAMESPACE = "__fynixLinkProps__";
|
|
@@ -10,6 +16,7 @@ function escapeHTML(str) {
|
|
|
10
16
|
return "";
|
|
11
17
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/`/g, "`").replace(/\//g, "/");
|
|
12
18
|
}
|
|
19
|
+
__name(escapeHTML, "escapeHTML");
|
|
13
20
|
function isValidURL(url) {
|
|
14
21
|
try {
|
|
15
22
|
const parsed = new URL(url, window.location.origin);
|
|
@@ -18,7 +25,10 @@ function isValidURL(url) {
|
|
|
18
25
|
return false;
|
|
19
26
|
}
|
|
20
27
|
if (!ALLOWED_PROTOCOLS.includes(parsed.protocol)) {
|
|
21
|
-
console.warn(
|
|
28
|
+
console.warn(
|
|
29
|
+
"[Router] Security: Dangerous protocol blocked:",
|
|
30
|
+
parsed.protocol
|
|
31
|
+
);
|
|
22
32
|
return false;
|
|
23
33
|
}
|
|
24
34
|
return true;
|
|
@@ -27,6 +37,7 @@ function isValidURL(url) {
|
|
|
27
37
|
return false;
|
|
28
38
|
}
|
|
29
39
|
}
|
|
40
|
+
__name(isValidURL, "isValidURL");
|
|
30
41
|
function sanitizePath(path) {
|
|
31
42
|
if (typeof path !== "string")
|
|
32
43
|
return "/";
|
|
@@ -48,15 +59,19 @@ function sanitizePath(path) {
|
|
|
48
59
|
}
|
|
49
60
|
return path || "/";
|
|
50
61
|
}
|
|
62
|
+
__name(sanitizePath, "sanitizePath");
|
|
51
63
|
function tryGlobPaths() {
|
|
52
64
|
try {
|
|
53
|
-
const modules = import.meta.glob("/src/**/*.{ts,js,jsx,fnx}", {
|
|
65
|
+
const modules = import.meta.glob("/src/**/*.{ts,js,jsx,fnx}", {
|
|
66
|
+
eager: true
|
|
67
|
+
});
|
|
54
68
|
return modules || {};
|
|
55
69
|
} catch (error) {
|
|
56
70
|
console.error("[Router] Failed to load modules:", error);
|
|
57
71
|
return {};
|
|
58
72
|
}
|
|
59
73
|
}
|
|
74
|
+
__name(tryGlobPaths, "tryGlobPaths");
|
|
60
75
|
function filePathToRoute(filePath) {
|
|
61
76
|
let route = filePath.replace(/^.*\/src/, "").replace(/\.(js|jsx|fnx)$/, "").replace(/\/view$/, "").replace(/\/$/, "");
|
|
62
77
|
if (!route)
|
|
@@ -64,6 +79,7 @@ function filePathToRoute(filePath) {
|
|
|
64
79
|
route = route.replace(/\[([^\]]+)\]/g, ":$1");
|
|
65
80
|
return route;
|
|
66
81
|
}
|
|
82
|
+
__name(filePathToRoute, "filePathToRoute");
|
|
67
83
|
function matchDynamicRoute(path, dynamicRoutes) {
|
|
68
84
|
for (const route of dynamicRoutes) {
|
|
69
85
|
const match = path.match(route.regex);
|
|
@@ -77,6 +93,7 @@ function matchDynamicRoute(path, dynamicRoutes) {
|
|
|
77
93
|
}
|
|
78
94
|
return null;
|
|
79
95
|
}
|
|
96
|
+
__name(matchDynamicRoute, "matchDynamicRoute");
|
|
80
97
|
function deserializeProps(props) {
|
|
81
98
|
if (!props || typeof props !== "object")
|
|
82
99
|
return {};
|
|
@@ -89,19 +106,24 @@ function deserializeProps(props) {
|
|
|
89
106
|
}
|
|
90
107
|
return deserialized;
|
|
91
108
|
}
|
|
109
|
+
__name(deserializeProps, "deserializeProps");
|
|
92
110
|
function normalizePath(path) {
|
|
93
111
|
return sanitizePath(path);
|
|
94
112
|
}
|
|
113
|
+
__name(normalizePath, "normalizePath");
|
|
95
114
|
function generateCacheKey() {
|
|
96
115
|
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
97
116
|
return crypto.randomUUID();
|
|
98
117
|
}
|
|
99
118
|
return `${Date.now()}-${Math.random().toString(36).slice(2)}-${Math.random().toString(36).slice(2)}`;
|
|
100
119
|
}
|
|
120
|
+
__name(generateCacheKey, "generateCacheKey");
|
|
101
121
|
function createFynix() {
|
|
102
122
|
const isDevMode = import.meta.hot !== void 0;
|
|
103
123
|
if (routerInstance && isRouterInitialized && !isDevMode) {
|
|
104
|
-
console.warn(
|
|
124
|
+
console.warn(
|
|
125
|
+
"[Router] Router already initialized, returning existing instance"
|
|
126
|
+
);
|
|
105
127
|
return routerInstance;
|
|
106
128
|
}
|
|
107
129
|
if (isDevMode && routerInstance) {
|
|
@@ -161,6 +183,7 @@ function createFynix() {
|
|
|
161
183
|
}
|
|
162
184
|
__fynixPropsCache.set(key, value);
|
|
163
185
|
}
|
|
186
|
+
__name(addToCache, "addToCache");
|
|
164
187
|
const MANAGED_META = [
|
|
165
188
|
{ key: "description", name: "description" },
|
|
166
189
|
{ key: "keywords", name: "keywords" },
|
|
@@ -197,6 +220,7 @@ function createFynix() {
|
|
|
197
220
|
el.setAttribute("content", escapeHTML(value));
|
|
198
221
|
});
|
|
199
222
|
}
|
|
223
|
+
__name(updateMetaTags, "updateMetaTags");
|
|
200
224
|
let renderTimeout = null;
|
|
201
225
|
const RENDER_DEBOUNCE = 10;
|
|
202
226
|
function renderRoute() {
|
|
@@ -210,6 +234,7 @@ function createFynix() {
|
|
|
210
234
|
renderTimeout = null;
|
|
211
235
|
}, RENDER_DEBOUNCE);
|
|
212
236
|
}
|
|
237
|
+
__name(renderRoute, "renderRoute");
|
|
213
238
|
function _renderRouteImmediate() {
|
|
214
239
|
if (isDestroyed)
|
|
215
240
|
return;
|
|
@@ -261,6 +286,7 @@ function createFynix() {
|
|
|
261
286
|
}
|
|
262
287
|
currentPath = path;
|
|
263
288
|
}
|
|
289
|
+
__name(_renderRouteImmediate, "_renderRouteImmediate");
|
|
264
290
|
function navigate(path, props = {}) {
|
|
265
291
|
if (isDestroyed)
|
|
266
292
|
return;
|
|
@@ -280,6 +306,7 @@ function createFynix() {
|
|
|
280
306
|
console.error("[Router] Navigation failed:", err);
|
|
281
307
|
}
|
|
282
308
|
}
|
|
309
|
+
__name(navigate, "navigate");
|
|
283
310
|
function replace(path, props = {}) {
|
|
284
311
|
if (isDestroyed)
|
|
285
312
|
return;
|
|
@@ -297,6 +324,7 @@ function createFynix() {
|
|
|
297
324
|
console.error("[Router] Replace failed:", err);
|
|
298
325
|
}
|
|
299
326
|
}
|
|
327
|
+
__name(replace, "replace");
|
|
300
328
|
function back() {
|
|
301
329
|
if (isDestroyed)
|
|
302
330
|
return;
|
|
@@ -306,6 +334,7 @@ function createFynix() {
|
|
|
306
334
|
console.error("[Router] Back navigation failed:", err);
|
|
307
335
|
}
|
|
308
336
|
}
|
|
337
|
+
__name(back, "back");
|
|
309
338
|
function mountRouter(selector = "#app-root") {
|
|
310
339
|
if (isDestroyed) {
|
|
311
340
|
console.error("[Router] Cannot mount destroyed router");
|
|
@@ -319,7 +348,8 @@ function createFynix() {
|
|
|
319
348
|
renderRoute();
|
|
320
349
|
isRouterInitialized = true;
|
|
321
350
|
}
|
|
322
|
-
|
|
351
|
+
__name(mountRouter, "mountRouter");
|
|
352
|
+
const clickHandler = /* @__PURE__ */ __name((e) => {
|
|
323
353
|
if (isDestroyed)
|
|
324
354
|
return;
|
|
325
355
|
const link = e.target.closest("a[data-fynix-link]");
|
|
@@ -330,13 +360,18 @@ function createFynix() {
|
|
|
330
360
|
console.warn("[Router] Missing href attribute");
|
|
331
361
|
return;
|
|
332
362
|
}
|
|
363
|
+
if (isExternal(href)) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
333
366
|
const fullUrl = new URL(link.href, window.location.origin).href;
|
|
334
367
|
if (!isValidURL(fullUrl)) {
|
|
335
368
|
console.warn("[Router] Invalid link href");
|
|
336
369
|
return;
|
|
337
370
|
}
|
|
338
371
|
e.preventDefault();
|
|
339
|
-
const path = normalizePath(
|
|
372
|
+
const path = normalizePath(
|
|
373
|
+
new URL(link.href, window.location.origin).pathname
|
|
374
|
+
);
|
|
340
375
|
if (path === currentPath)
|
|
341
376
|
return;
|
|
342
377
|
let props = {};
|
|
@@ -364,13 +399,21 @@ function createFynix() {
|
|
|
364
399
|
} catch (err) {
|
|
365
400
|
console.error("[Router] Link navigation failed:", err);
|
|
366
401
|
}
|
|
367
|
-
};
|
|
402
|
+
}, "clickHandler");
|
|
368
403
|
if (listenerCount < MAX_LISTENERS && !isRouterInitialized) {
|
|
369
404
|
document.addEventListener("click", clickHandler);
|
|
370
|
-
listeners.push({
|
|
405
|
+
listeners.push({
|
|
406
|
+
element: document,
|
|
407
|
+
event: "click",
|
|
408
|
+
handler: clickHandler
|
|
409
|
+
});
|
|
371
410
|
listenerCount++;
|
|
372
411
|
window.addEventListener("popstate", renderRoute);
|
|
373
|
-
listeners.push({
|
|
412
|
+
listeners.push({
|
|
413
|
+
element: window,
|
|
414
|
+
event: "popstate",
|
|
415
|
+
handler: renderRoute
|
|
416
|
+
});
|
|
374
417
|
listenerCount++;
|
|
375
418
|
}
|
|
376
419
|
function cleanup() {
|
|
@@ -414,6 +457,7 @@ function createFynix() {
|
|
|
414
457
|
routerInstance = null;
|
|
415
458
|
console.log("[Router] Cleanup complete");
|
|
416
459
|
}
|
|
460
|
+
__name(cleanup, "cleanup");
|
|
417
461
|
if (import.meta.hot) {
|
|
418
462
|
import.meta.hot.accept(() => {
|
|
419
463
|
console.log("[Router] HMR detected, re-rendering route...");
|
|
@@ -438,6 +482,7 @@ function createFynix() {
|
|
|
438
482
|
routerInstance = router;
|
|
439
483
|
return router;
|
|
440
484
|
}
|
|
485
|
+
__name(createFynix, "createFynix");
|
|
441
486
|
function setLinkProps(key, props) {
|
|
442
487
|
if (typeof key !== "string" || key.startsWith("__")) {
|
|
443
488
|
console.error("[Router] Invalid props key");
|
|
@@ -456,6 +501,7 @@ function setLinkProps(key, props) {
|
|
|
456
501
|
}
|
|
457
502
|
window[PROPS_NAMESPACE][key] = props;
|
|
458
503
|
}
|
|
504
|
+
__name(setLinkProps, "setLinkProps");
|
|
459
505
|
function clearLinkProps(key) {
|
|
460
506
|
if (typeof key !== "string")
|
|
461
507
|
return;
|
|
@@ -474,6 +520,7 @@ function clearLinkProps(key) {
|
|
|
474
520
|
delete window[PROPS_NAMESPACE][key];
|
|
475
521
|
}
|
|
476
522
|
}
|
|
523
|
+
__name(clearLinkProps, "clearLinkProps");
|
|
477
524
|
export {
|
|
478
525
|
clearLinkProps,
|
|
479
526
|
createFynix,
|
|
@@ -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, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"')\r\n .replace(/'/g, ''')\r\n .replace(/`/g, '`')\r\n .replace(/\\//g, '/');\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, \"&\")\r\n .replace(/</g, \"<\")\r\n .replace(/>/g, \">\")\r\n .replace(/\"/g, \""\")\r\n .replace(/'/g, \"'\")\r\n .replace(/`/g, \"`\")\r\n .replace(/\\//g, \"/\");\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
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a virtual text node, supporting reactive state.
|
|
3
|
+
* @param {string|number|object} text
|
|
4
|
+
* @returns {object} vnode
|
|
5
|
+
*/
|
|
6
|
+
export function createTextVNode(text: string | number | object): object;
|
|
7
|
+
/**
|
|
8
|
+
* Create a virtual DOM node (element, fragment, or component).
|
|
9
|
+
* @param {string|function|symbol} type
|
|
10
|
+
* @param {object} [props={}]
|
|
11
|
+
* @param {...any} children
|
|
12
|
+
* @returns {object} vnode
|
|
13
|
+
*/
|
|
14
|
+
export function h(type: string | Function | symbol, props?: object, ...children: any[]): object;
|
|
15
|
+
export namespace h {
|
|
16
|
+
function Fragment({ children }: {
|
|
17
|
+
children: any;
|
|
18
|
+
}): any;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Safely render a component
|
|
22
|
+
* @param {function} Component
|
|
23
|
+
* @param {object} props
|
|
24
|
+
* @returns {object} vnode
|
|
25
|
+
*/
|
|
26
|
+
export function renderComponent(Component: Function, props?: object): object;
|
|
27
|
+
/**
|
|
28
|
+
* Patch a parent DOM node based on oldVNode -> newVNode changes
|
|
29
|
+
* @param {Node} parent
|
|
30
|
+
* @param {object|string|number} newVNode
|
|
31
|
+
* @param {object|string|number} oldVNode
|
|
32
|
+
* @returns {Promise<void>}
|
|
33
|
+
*/
|
|
34
|
+
export function patch(parent: Node, newVNode: object | string | number, oldVNode: object | string | number): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Mount the app component to a root DOM node
|
|
37
|
+
* @param {function} AppComponent
|
|
38
|
+
* @param {string|Element} root
|
|
39
|
+
* @param {boolean} [hydrate=false]
|
|
40
|
+
* @param {object} [props={}]
|
|
41
|
+
*/
|
|
42
|
+
export function mount(AppComponent: Function, root: string | Element, hydrate?: boolean, props?: object): void;
|
|
43
|
+
/**
|
|
44
|
+
* Symbol for text nodes
|
|
45
|
+
* @type {symbol}
|
|
46
|
+
*/
|
|
47
|
+
export const TEXT: symbol;
|
|
48
|
+
/**
|
|
49
|
+
* Symbol for fragments
|
|
50
|
+
* @type {symbol}
|
|
51
|
+
*/
|
|
52
|
+
export const Fragment: symbol;
|
|
53
|
+
/**
|
|
54
|
+
* Create a virtual DOM node (element, fragment, or component).
|
|
55
|
+
* @param {string|function|symbol} type
|
|
56
|
+
* @param {object} [props={}]
|
|
57
|
+
* @param {...any} children
|
|
58
|
+
* @returns {object} vnode
|
|
59
|
+
*/
|
|
60
|
+
export function Fynix(type: string | Function | symbol, props?: object, ...children: any[]): object;
|
|
61
|
+
export namespace Fynix {
|
|
62
|
+
import Fragment = h.Fragment;
|
|
63
|
+
export { Fragment };
|
|
64
|
+
}
|
|
65
|
+
import { nixState } from "./hooks/nixState";
|
|
66
|
+
import { nixEffect } from "./hooks/nixEffect";
|
|
67
|
+
import { nixStore } from "./hooks/nixStore";
|
|
68
|
+
import { nixInterval } from "./hooks/nixInterval";
|
|
69
|
+
import { nixAsync } from "./hooks/nixAsync";
|
|
70
|
+
import { nixCallback } from "./hooks/nixCallback";
|
|
71
|
+
import { nixComputed } from "./hooks/nixComputed";
|
|
72
|
+
import { nixMemo } from "./hooks/nixMemo";
|
|
73
|
+
import { nixDebounce } from "./hooks/nixDebounce";
|
|
74
|
+
import { nixPrevious } from "./hooks/nixPrevious";
|
|
75
|
+
import { nixLocalStorage } from "./hooks/nixLocalStorage";
|
|
76
|
+
import { nixRef } from "./hooks/nixRef";
|
|
77
|
+
import { nixLazy } from "./hooks/nixLazy.js";
|
|
78
|
+
import { Suspense } from "./hooks/nixLazy.js";
|
|
79
|
+
import { nixForm } from "./hooks/nixForm.js";
|
|
80
|
+
import { nixAsyncCached } from "./hooks/nixAsyncCache";
|
|
81
|
+
import { nixAsyncDebounce } from "./hooks/nixAsyncDebounce";
|
|
82
|
+
import { nixAsyncQuery } from "./hooks/nixAsyncQuery";
|
|
83
|
+
import { nixEffectAlways } from "./hooks/nixEffect";
|
|
84
|
+
import { nixEffectOnce } from "./hooks/nixEffect";
|
|
85
|
+
import { nixFormAsync } from "./hooks/nixFormAsync";
|
|
86
|
+
import { nixLazyAsync } from "./hooks/nixLazyAsync";
|
|
87
|
+
import { nixLazyFormAsync } from "./hooks/nixLazyFormAsync";
|
|
88
|
+
import { Path } from "./custom/index.js";
|
|
89
|
+
import { Button } from "./custom/index.js";
|
|
90
|
+
import createFynix from "./router/router.js";
|
|
91
|
+
export { nixState, nixEffect, nixStore, nixInterval, nixAsync, nixCallback, nixComputed, nixMemo, nixDebounce, nixPrevious, nixLocalStorage, nixRef, nixLazy, Suspense, nixForm, nixAsyncCached, nixAsyncDebounce, nixAsyncQuery, nixEffectAlways, nixEffectOnce, nixFormAsync, nixLazyAsync, nixLazyFormAsync, Path, Button, createFynix };
|
package/dist/runtime.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
1
3
|
import { removeErrorOverlay, showErrorOverlay } from "./error/errorOverlay";
|
|
2
4
|
import { setActiveContext, activeContext } from "./context/context.js";
|
|
3
5
|
import { nixStore } from "./hooks/nixStore";
|
|
@@ -74,6 +76,7 @@ function createTextVNode(text) {
|
|
|
74
76
|
}
|
|
75
77
|
return { type: TEXT, props: { nodeValue: String(text) }, key: null };
|
|
76
78
|
}
|
|
79
|
+
__name(createTextVNode, "createTextVNode");
|
|
77
80
|
function h(type, props = {}, ...children) {
|
|
78
81
|
if (props === null || typeof props !== "object" || Array.isArray(props))
|
|
79
82
|
props = {};
|
|
@@ -101,6 +104,7 @@ function h(type, props = {}, ...children) {
|
|
|
101
104
|
return { type: Fragment, props: { children: flatChildren }, key };
|
|
102
105
|
return { type, props: { ...props, children: flatChildren }, key };
|
|
103
106
|
}
|
|
107
|
+
__name(h, "h");
|
|
104
108
|
h.Fragment = ({ children }) => children;
|
|
105
109
|
const Fynix = h;
|
|
106
110
|
Fynix.Fragment = h.Fragment;
|
|
@@ -120,7 +124,8 @@ function beginComponent(vnode) {
|
|
|
120
124
|
_subscriptions: /* @__PURE__ */ new Set(),
|
|
121
125
|
_subscriptionCleanups: [],
|
|
122
126
|
version: 0,
|
|
123
|
-
|
|
127
|
+
/** @type {undefined | (() => void)} */
|
|
128
|
+
rerender: void 0,
|
|
124
129
|
Component: vnode.type,
|
|
125
130
|
_isMounted: false,
|
|
126
131
|
_isRerendering: false
|
|
@@ -133,6 +138,7 @@ function beginComponent(vnode) {
|
|
|
133
138
|
ctx.version++;
|
|
134
139
|
return ctx;
|
|
135
140
|
}
|
|
141
|
+
__name(beginComponent, "beginComponent");
|
|
136
142
|
function endComponent() {
|
|
137
143
|
const ctx = activeContext;
|
|
138
144
|
if (!ctx)
|
|
@@ -141,7 +147,7 @@ function endComponent() {
|
|
|
141
147
|
if (!ctx._subscriptions.has(state)) {
|
|
142
148
|
if (!ctx.rerender) {
|
|
143
149
|
let rerenderTimeout = null;
|
|
144
|
-
ctx.rerender = ()
|
|
150
|
+
ctx.rerender = /* @__PURE__ */ __name(function rerender() {
|
|
145
151
|
if (ctx._isRerendering || pendingRerenders.has(ctx)) {
|
|
146
152
|
return;
|
|
147
153
|
}
|
|
@@ -186,12 +192,12 @@ function endComponent() {
|
|
|
186
192
|
}
|
|
187
193
|
rerenderTimeout = null;
|
|
188
194
|
}, 0);
|
|
189
|
-
};
|
|
195
|
+
}, "rerender");
|
|
190
196
|
}
|
|
191
197
|
const unsub = state.subscribe(() => {
|
|
192
198
|
if (ctx.rerender && ctx._isMounted) {
|
|
193
199
|
if (typeof queueMicrotask === "function")
|
|
194
|
-
queueMicrotask(ctx.rerender);
|
|
200
|
+
queueMicrotask(() => ctx.rerender());
|
|
195
201
|
else
|
|
196
202
|
setTimeout(ctx.rerender, 0);
|
|
197
203
|
}
|
|
@@ -202,6 +208,7 @@ function endComponent() {
|
|
|
202
208
|
});
|
|
203
209
|
setActiveContext(null);
|
|
204
210
|
}
|
|
211
|
+
__name(endComponent, "endComponent");
|
|
205
212
|
function renderComponent(Component, props = {}) {
|
|
206
213
|
const vnode = { type: Component, props };
|
|
207
214
|
const ctx = beginComponent(vnode);
|
|
@@ -269,6 +276,7 @@ function renderComponent(Component, props = {}) {
|
|
|
269
276
|
endComponent();
|
|
270
277
|
}
|
|
271
278
|
}
|
|
279
|
+
__name(renderComponent, "renderComponent");
|
|
272
280
|
const delegatedEvents = /* @__PURE__ */ new Map();
|
|
273
281
|
let eventIdCounter = 1;
|
|
274
282
|
function ensureDelegated(eventType) {
|
|
@@ -290,6 +298,7 @@ function ensureDelegated(eventType) {
|
|
|
290
298
|
}
|
|
291
299
|
});
|
|
292
300
|
}
|
|
301
|
+
__name(ensureDelegated, "ensureDelegated");
|
|
293
302
|
function registerDelegatedHandler(el, eventName, fn) {
|
|
294
303
|
if (!fn || el.nodeType !== 1)
|
|
295
304
|
return;
|
|
@@ -304,6 +313,7 @@ function registerDelegatedHandler(el, eventName, fn) {
|
|
|
304
313
|
}
|
|
305
314
|
});
|
|
306
315
|
}
|
|
316
|
+
__name(registerDelegatedHandler, "registerDelegatedHandler");
|
|
307
317
|
function setProperty(el, key, value) {
|
|
308
318
|
const k = key.toLowerCase();
|
|
309
319
|
if (key === "r-class" || key === "rc") {
|
|
@@ -364,6 +374,7 @@ function setProperty(el, key, value) {
|
|
|
364
374
|
if (value != null && value !== false)
|
|
365
375
|
el.setAttribute(key, value);
|
|
366
376
|
}
|
|
377
|
+
__name(setProperty, "setProperty");
|
|
367
378
|
async function createDom(vnode, existing = null) {
|
|
368
379
|
if (vnode == null || vnode === false)
|
|
369
380
|
return document.createTextNode("");
|
|
@@ -423,6 +434,7 @@ async function createDom(vnode, existing = null) {
|
|
|
423
434
|
vnode._domNode = el;
|
|
424
435
|
return el;
|
|
425
436
|
}
|
|
437
|
+
__name(createDom, "createDom");
|
|
426
438
|
async function renderMaybeAsyncComponent(Component, props, vnode) {
|
|
427
439
|
const ctx = beginComponent(vnode);
|
|
428
440
|
removeErrorOverlay();
|
|
@@ -441,6 +453,7 @@ async function renderMaybeAsyncComponent(Component, props, vnode) {
|
|
|
441
453
|
return h("div", { style: "color:red" }, `Error: ${err.message}`);
|
|
442
454
|
}
|
|
443
455
|
}
|
|
456
|
+
__name(renderMaybeAsyncComponent, "renderMaybeAsyncComponent");
|
|
444
457
|
async function patch(parent, newVNode, oldVNode) {
|
|
445
458
|
if (!(parent instanceof Node)) {
|
|
446
459
|
console.error(
|
|
@@ -565,6 +578,7 @@ async function patch(parent, newVNode, oldVNode) {
|
|
|
565
578
|
const oldChildren = oldVNode.props?.children || [];
|
|
566
579
|
await patchChildren(el, newChildren, oldChildren);
|
|
567
580
|
}
|
|
581
|
+
__name(patch, "patch");
|
|
568
582
|
async function patchChildren(parent, newChildren, oldChildren) {
|
|
569
583
|
if (!(parent instanceof Node))
|
|
570
584
|
return;
|
|
@@ -635,6 +649,7 @@ async function patchChildren(parent, newChildren, oldChildren) {
|
|
|
635
649
|
}
|
|
636
650
|
}
|
|
637
651
|
}
|
|
652
|
+
__name(patchChildren, "patchChildren");
|
|
638
653
|
function unmountVNode(vnode) {
|
|
639
654
|
if (!vnode)
|
|
640
655
|
return;
|
|
@@ -699,6 +714,7 @@ function unmountVNode(vnode) {
|
|
|
699
714
|
vnode._domNode = null;
|
|
700
715
|
vnode._rendered = null;
|
|
701
716
|
}
|
|
717
|
+
__name(unmountVNode, "unmountVNode");
|
|
702
718
|
function updateProps(el, newProps = {}, oldProps = {}) {
|
|
703
719
|
if (!el || el.nodeType !== 1)
|
|
704
720
|
return;
|
|
@@ -727,6 +743,7 @@ function updateProps(el, newProps = {}, oldProps = {}) {
|
|
|
727
743
|
setProperty(el, k, v);
|
|
728
744
|
}
|
|
729
745
|
}
|
|
746
|
+
__name(updateProps, "updateProps");
|
|
730
747
|
function mount(AppComponent, root, hydrate = false, props = {}) {
|
|
731
748
|
if (typeof root === "string") {
|
|
732
749
|
const element = document.querySelector(root);
|
|
@@ -786,6 +803,7 @@ function mount(AppComponent, root, hydrate = false, props = {}) {
|
|
|
786
803
|
isRendering = false;
|
|
787
804
|
}
|
|
788
805
|
}
|
|
806
|
+
__name(renderApp, "renderApp");
|
|
789
807
|
rootRenderFn = renderApp;
|
|
790
808
|
window.__fynix__ = window.__fynix__ || {};
|
|
791
809
|
window.__fynix__.rerender = renderApp;
|
|
@@ -811,6 +829,7 @@ function mount(AppComponent, root, hydrate = false, props = {}) {
|
|
|
811
829
|
}
|
|
812
830
|
}
|
|
813
831
|
}
|
|
832
|
+
__name(mount, "mount");
|
|
814
833
|
export {
|
|
815
834
|
Button,
|
|
816
835
|
Fragment,
|