viewlogic 1.2.4 โ†’ 1.2.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/README.md CHANGED
@@ -12,11 +12,11 @@
12
12
  </a>
13
13
  </p>
14
14
 
15
- > **Complete Vue 3 Framework**: All-in-one solution for modern web development
15
+ > **AI-First Vue 3 Framework**: The future of web development in the age of artificial intelligence
16
16
 
17
17
  ## ๐ŸŽฏ Core Philosophy
18
18
 
19
- ViewLogic Router revolutionizes Vue development with two fundamental principles:
19
+ ViewLogic Router revolutionizes Vue development with three fundamental principles:
20
20
 
21
21
  ### ๐ŸŽญ View-Logic Separation
22
22
  **Complete separation between View (presentation) and Logic (business logic)**. Views are pure HTML templates, logic is pure JavaScript components. This separation makes your code more maintainable, testable, and scalable.
@@ -24,6 +24,9 @@ ViewLogic Router revolutionizes Vue development with two fundamental principles:
24
24
  ### ๐Ÿš€ Zero Build Development
25
25
  **Zero build step required in development mode**. Work directly with source files, see changes instantly without any compilation, bundling, or build processes. True real-time development experience.
26
26
 
27
+ ### ๐Ÿค– AI-First Architecture
28
+ **Built from the ground up for the AI coding era**. Clear conventions, predictable patterns, and separated concerns make ViewLogic the perfect framework for AI-assisted development. Generate pages, components, and logic with AI tools seamlessly.
29
+
27
30
  ## โœจ What Makes ViewLogic Special
28
31
 
29
32
  **All-in-One Solution** - Replace multiple libraries with one unified framework:
@@ -187,33 +190,23 @@ export default {
187
190
 
188
191
  **src/layouts/default.html** (optional)
189
192
  ```html
190
- <!DOCTYPE html>
191
- <html>
192
- <head>
193
- <title>My ViewLogic App</title>
194
- <meta charset="utf-8">
195
- <meta name="viewport" content="width=device-width, initial-scale=1">
196
- </head>
197
- <body>
198
- <header class="navbar">
199
- <h1>My App</h1>
200
- <nav>
201
- <a href="#/home">Home</a>
202
- <a href="#/about">About</a>
203
- </nav>
204
- </header>
205
-
206
- <main class="main-content">
207
- <div class="container">
208
- {{ content }}
209
- </div>
210
- </main>
211
-
212
- <footer>
213
- <p>&copy; 2024 My ViewLogic App</p>
214
- </footer>
215
- </body>
216
- </html>
193
+ <header class="navbar">
194
+ <h1>My App</h1>
195
+ <nav>
196
+ <a href="#/home">Home</a>
197
+ <a href="#/about">About</a>
198
+ </nav>
199
+ </header>
200
+
201
+ <main class="main-content">
202
+ <div class="container">
203
+ {{ content }}
204
+ </div>
205
+ </main>
206
+
207
+ <footer>
208
+ <p>&copy; 2024 My ViewLogic App</p>
209
+ </footer>
217
210
  ```
218
211
 
219
212
  ### Query Parameter Example
@@ -357,7 +350,8 @@ if (this.$state.has('user')) {
357
350
  // Watch for changes (reactive)
358
351
  this.$state.watch('user', (newValue, oldValue) => {
359
352
  console.log('User changed:', newValue);
360
- this.updateUI();
353
+ // Update component data to trigger reactivity
354
+ this.currentUser = newValue;
361
355
  });
362
356
 
363
357
  // Bulk updates
@@ -389,8 +383,7 @@ this.setToken('jwt-token-here');
389
383
 
390
384
  // Login with options
391
385
  this.setToken('jwt-token', {
392
- storage: 'localStorage', // 'localStorage', 'sessionStorage', 'cookie'
393
- skipValidation: false // Skip JWT validation
386
+ storage: 'localStorage' // 'localStorage', 'sessionStorage', 'cookie'
394
387
  });
395
388
 
396
389
  // Get current token
@@ -685,8 +678,9 @@ const router = new ViewLogicRouter({
685
678
  maxCacheSize: 100, // Maximum number of cached items
686
679
 
687
680
  // API settings
688
- apiBaseURL: '/api', // Base URL for API requests
689
- apiTimeout: 10000, // Request timeout in milliseconds
681
+ apiBaseURL: 'https://api.example.com/v1', // Base URL for API requests
682
+ requestTimeout: 30000, // Form submission timeout in milliseconds (30 seconds)
683
+ uploadTimeout: 300000, // File upload timeout in milliseconds (5 minutes)
690
684
 
691
685
  // Development settings
692
686
  environment: 'development', // 'development' or 'production'
@@ -355,8 +355,7 @@ var AuthManager = class {
355
355
  checkAuthFunction: options.checkAuthFunction || null,
356
356
  redirectAfterLogin: options.redirectAfterLogin || "home",
357
357
  authCookieName: options.authCookieName || "authToken",
358
- authStorage: options.authStorage || "localStorage",
359
- authSkipValidation: options.authSkipValidation || false
358
+ authStorage: options.authStorage || "localStorage"
360
359
  };
361
360
  this.router = router;
362
361
  this.eventListeners = /* @__PURE__ */ new Map();
@@ -510,11 +509,10 @@ var AuthManager = class {
510
509
  }
511
510
  const {
512
511
  storage = this.config.authStorage,
513
- cookieOptions = this.config.authCookieOptions,
514
- skipValidation = this.config.authSkipValidation
512
+ cookieOptions = this.config.authCookieOptions
515
513
  } = options;
516
514
  try {
517
- if (!skipValidation && !this.isTokenValid(token)) {
515
+ if (!this.isTokenValid(token)) {
518
516
  this.log("warn", "\u274C Token is expired or invalid");
519
517
  return false;
520
518
  }
@@ -541,7 +539,7 @@ var AuthManager = class {
541
539
  });
542
540
  return true;
543
541
  } catch (error) {
544
- this.log("Failed to set token:", error);
542
+ this.log("error", "Failed to set token:", error);
545
543
  return false;
546
544
  }
547
545
  }
@@ -592,14 +590,14 @@ var AuthManager = class {
592
590
  break;
593
591
  }
594
592
  this.emitAuthEvent("token_removed", { storage });
595
- this.log(`Token removed from: ${storage}`);
593
+ this.log("debug", `Token removed from: ${storage}`);
596
594
  }
597
595
  /**
598
596
  * ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์ฒ˜๋ฆฌ
599
597
  */
600
598
  loginSuccess(targetRoute = null) {
601
599
  const redirectRoute = targetRoute || this.config.redirectAfterLogin;
602
- this.log(`\u{1F389} Login success, redirecting to: ${redirectRoute}`);
600
+ this.log("info", `\u{1F389} Login success, redirecting to: ${redirectRoute}`);
603
601
  this.emitAuthEvent("login_success", { targetRoute: redirectRoute });
604
602
  if (this.router && typeof this.router.navigateTo === "function") {
605
603
  this.router.navigateTo(redirectRoute);
@@ -610,7 +608,7 @@ var AuthManager = class {
610
608
  * ๋กœ๊ทธ์•„์›ƒ ์ฒ˜๋ฆฌ
611
609
  */
612
610
  logout() {
613
- this.log("\u{1F44B} Logging out user");
611
+ this.log("info", "\u{1F44B} Logging out user");
614
612
  this.removeAccessToken();
615
613
  this.emitAuthEvent("logout", {});
616
614
  if (this.router && typeof this.router.navigateTo === "function") {
@@ -635,11 +633,11 @@ var AuthManager = class {
635
633
  try {
636
634
  listener(data);
637
635
  } catch (error) {
638
- this.log("Event listener error:", error);
636
+ this.log("error", "Event listener error:", error);
639
637
  }
640
638
  });
641
639
  }
642
- this.log(`\u{1F514} Auth event emitted: ${eventType}`, data);
640
+ this.log("debug", `\u{1F514} Auth event emitted: ${eventType}`, data);
643
641
  }
644
642
  /**
645
643
  * ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ๋“ฑ๋ก
@@ -812,7 +810,7 @@ var CacheManager = class {
812
810
  patterns.forEach((pattern) => {
813
811
  totalInvalidated += this.deleteByPattern(pattern);
814
812
  });
815
- this.log(`\u{1F504} Deleted component cache for route: ${routeName} (${totalInvalidated} entries)`);
813
+ this.log("debug", `\u{1F504} Deleted component cache for route: ${routeName} (${totalInvalidated} entries)`);
816
814
  return totalInvalidated;
817
815
  }
818
816
  /**
@@ -824,7 +822,7 @@ var CacheManager = class {
824
822
  componentPatterns.forEach((pattern) => {
825
823
  totalCleared += this.deleteByPattern(pattern);
826
824
  });
827
- this.log(`\u{1F9FD} Deleted all component caches (${totalCleared} entries)`);
825
+ this.log("debug", `\u{1F9FD} Deleted all component caches (${totalCleared} entries)`);
828
826
  return totalCleared;
829
827
  }
830
828
  /**
@@ -835,7 +833,7 @@ var CacheManager = class {
835
833
  this.cache.clear();
836
834
  this.cacheTimestamps.clear();
837
835
  this.lruOrder = [];
838
- this.log(`\u{1F525} Cleared all cache (${size} entries)`);
836
+ this.log("debug", `\u{1F525} Cleared all cache (${size} entries)`);
839
837
  return size;
840
838
  }
841
839
  /**
@@ -860,7 +858,7 @@ var CacheManager = class {
860
858
  }
861
859
  });
862
860
  if (expiredKeys.length > 0) {
863
- this.log(`\u23F1\uFE0F Cleaned ${expiredKeys.length} expired cache entries`);
861
+ this.log("debug", `\u23F1\uFE0F Cleaned ${expiredKeys.length} expired cache entries`);
864
862
  }
865
863
  return expiredKeys.length;
866
864
  }
@@ -952,7 +950,7 @@ var CacheManager = class {
952
950
  this.cleanupInterval = setInterval(() => {
953
951
  this.cleanExpired();
954
952
  }, interval);
955
- this.log(`\u{1F916} Auto cleanup started (interval: ${interval}ms)`);
953
+ this.log("debug", `\u{1F916} Auto cleanup started (interval: ${interval}ms)`);
956
954
  }
957
955
  /**
958
956
  * ์ž๋™ ์ •๋ฆฌ ์ค‘์ง€
@@ -1174,11 +1172,8 @@ var QueryManager = class {
1174
1172
  var FormHandler = class {
1175
1173
  constructor(router, options = {}) {
1176
1174
  this.router = router;
1177
- this.config = {
1178
- debug: options.debug || false,
1179
- requestTimeout: options.requestTimeout || 3e4,
1180
- ...options
1181
- };
1175
+ this.requestTimeout = options.requestTimeout || 3e4;
1176
+ this.uploadTimeout = options.uploadTimeout || 3e5;
1182
1177
  this.log("debug", "FormHandler initialized");
1183
1178
  }
1184
1179
  /**
@@ -1205,11 +1200,13 @@ var FormHandler = class {
1205
1200
  startFormSubmission(form) {
1206
1201
  form._isSubmitting = true;
1207
1202
  form._abortController = new AbortController();
1203
+ const hasFile = Array.from(form.elements).some((el) => el.type === "file" && el.files.length > 0);
1204
+ const timeout = hasFile ? this.uploadTimeout : this.requestTimeout;
1208
1205
  form._timeoutId = setTimeout(() => {
1209
1206
  if (form._isSubmitting) {
1210
1207
  this.abortFormSubmission(form);
1211
1208
  }
1212
- }, this.config.requestTimeout);
1209
+ }, timeout);
1213
1210
  }
1214
1211
  /**
1215
1212
  * ํผ ์ œ์ถœ ์™„๋ฃŒ
@@ -1293,7 +1290,7 @@ var FormHandler = class {
1293
1290
  if (errorHandler && component[errorHandler]) {
1294
1291
  component[errorHandler](error, form);
1295
1292
  } else {
1296
- console.error("Form submission error:", error);
1293
+ this.log("error", "Form submission error (no error handler defined):", error);
1297
1294
  }
1298
1295
  } finally {
1299
1296
  if (loadingHandler && component[loadingHandler]) {
@@ -1413,12 +1410,7 @@ var FormHandler = class {
1413
1410
  var ApiHandler = class {
1414
1411
  constructor(router, options = {}) {
1415
1412
  this.router = router;
1416
- this.config = {
1417
- debug: options.debug || false,
1418
- timeout: options.timeout || 1e4,
1419
- retries: options.retries || 1,
1420
- ...options
1421
- };
1413
+ this.apiBaseURL = options.apiBaseURL || "";
1422
1414
  this.log("debug", "ApiHandler initialized");
1423
1415
  }
1424
1416
  /**
@@ -1435,6 +1427,9 @@ var ApiHandler = class {
1435
1427
  async fetchData(dataURL, component = null, options = {}) {
1436
1428
  try {
1437
1429
  let processedURL = this.processURLParameters(dataURL, component);
1430
+ if (this.apiBaseURL && !this.isAbsoluteURL(processedURL)) {
1431
+ processedURL = this.combineURLs(this.apiBaseURL, processedURL);
1432
+ }
1438
1433
  const queryString = this.router.queryManager?.buildQueryString(this.router.queryManager?.getQueryParams()) || "";
1439
1434
  const fullURL = queryString ? `${processedURL}?${queryString}` : processedURL;
1440
1435
  this.log("debug", `Fetching data from: ${fullURL}`);
@@ -1525,15 +1520,15 @@ var ApiHandler = class {
1525
1520
  const paramName = match.slice(1, -1);
1526
1521
  try {
1527
1522
  let paramValue = null;
1528
- if (component.getParam) {
1529
- paramValue = component.getParam(paramName);
1523
+ if (component.$options?.computed?.[paramName]) {
1524
+ paramValue = component[paramName];
1530
1525
  }
1531
1526
  if (paramValue === null || paramValue === void 0) {
1532
1527
  paramValue = component[paramName];
1533
1528
  }
1534
1529
  if (paramValue === null || paramValue === void 0) {
1535
- if (component.$options?.computed?.[paramName]) {
1536
- paramValue = component[paramName];
1530
+ if (component.getParam) {
1531
+ paramValue = component.getParam(paramName);
1537
1532
  }
1538
1533
  }
1539
1534
  if (paramValue === null || paramValue === void 0) {
@@ -1587,6 +1582,20 @@ var ApiHandler = class {
1587
1582
  fetchMultipleData: (dataConfig) => this.fetchMultipleData(dataConfig, component)
1588
1583
  };
1589
1584
  }
1585
+ /**
1586
+ * ์ ˆ๋Œ€ URL์ธ์ง€ ํ™•์ธ
1587
+ */
1588
+ isAbsoluteURL(url) {
1589
+ return /^https?:\/\//.test(url) || url.startsWith("//");
1590
+ }
1591
+ /**
1592
+ * ๋‘ URL์„ ์กฐํ•ฉ
1593
+ */
1594
+ combineURLs(baseURL, relativeURL) {
1595
+ const cleanBase = baseURL.replace(/\/$/, "");
1596
+ const cleanRelative = relativeURL.startsWith("/") ? relativeURL : `/${relativeURL}`;
1597
+ return `${cleanBase}${cleanRelative}`;
1598
+ }
1590
1599
  /**
1591
1600
  * ์ •๋ฆฌ (๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€)
1592
1601
  */
@@ -1602,7 +1611,6 @@ var ComponentLoader = class {
1602
1611
  this.config = {
1603
1612
  componentsPath: options.componentsPath || "/components",
1604
1613
  // srcPath ๊ธฐ์ค€ ์ƒ๋Œ€ ๊ฒฝ๋กœ
1605
- debug: options.debug || false,
1606
1614
  environment: options.environment || "development",
1607
1615
  ...options
1608
1616
  };
@@ -1873,8 +1881,7 @@ var RouteLoader = class {
1873
1881
  // ํ”„๋กœ๋•์…˜ ๋ผ์šฐํŠธ ๊ฒฝ๋กœ
1874
1882
  environment: options.environment || "development",
1875
1883
  useLayout: options.useLayout !== false,
1876
- defaultLayout: options.defaultLayout || "default",
1877
- debug: options.debug || false
1884
+ defaultLayout: options.defaultLayout || "default"
1878
1885
  };
1879
1886
  this.router = router;
1880
1887
  this.formHandler = new FormHandler(router, this.config);
@@ -2189,9 +2196,7 @@ ${template}`;
2189
2196
  var ErrorHandler = class {
2190
2197
  constructor(router, options = {}) {
2191
2198
  this.config = {
2192
- enableErrorReporting: options.enableErrorReporting !== false,
2193
- debug: options.debug || false,
2194
- logLevel: options.logLevel || (options.debug ? "debug" : "info"),
2199
+ logLevel: options.logLevel || "info",
2195
2200
  environment: options.environment || "development"
2196
2201
  };
2197
2202
  this.router = router;
@@ -2221,9 +2226,7 @@ var ErrorHandler = class {
2221
2226
  errorMessage = "\uD398\uC774\uC9C0\uC5D0 \uC811\uADFC\uD560 \uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.";
2222
2227
  }
2223
2228
  this.debug("ErrorHandler", `\uC5D0\uB7EC \uCF54\uB4DC \uACB0\uC815: ${errorCode} (\uB77C\uC6B0\uD2B8: ${routeName})`);
2224
- if (this.config.enableErrorReporting) {
2225
- this.reportError(routeName, error, errorCode);
2226
- }
2229
+ this.reportError(routeName, error, errorCode);
2227
2230
  try {
2228
2231
  if (errorCode === 404) {
2229
2232
  await this.load404Page();
@@ -2394,7 +2397,7 @@ var ErrorHandler = class {
2394
2397
  if (typeof level !== "string" || !this.logLevels.hasOwnProperty(level)) {
2395
2398
  args = [component, ...args];
2396
2399
  component = level;
2397
- level = this.config.debug ? "debug" : "info";
2400
+ level = "info";
2398
2401
  }
2399
2402
  const currentLevelValue = this.logLevels[this.config.logLevel] || this.logLevels.info;
2400
2403
  const messageLevelValue = this.logLevels[level] || this.logLevels.info;
@@ -2635,6 +2638,9 @@ var ViewLogicRouter = class {
2635
2638
  i18nPath: "/i18n",
2636
2639
  // ๋‹ค๊ตญ์–ด ํŒŒ์ผ ๊ฒฝ๋กœ
2637
2640
  logLevel: "info",
2641
+ apiBaseURL: "",
2642
+ requestTimeout: 3e4,
2643
+ uploadTimeout: 3e5,
2638
2644
  authEnabled: false,
2639
2645
  loginRoute: "login",
2640
2646
  protectedRoutes: [],
@@ -2643,8 +2649,7 @@ var ViewLogicRouter = class {
2643
2649
  checkAuthFunction: null,
2644
2650
  redirectAfterLogin: "home",
2645
2651
  authCookieName: "authToken",
2646
- authStorage: "localStorage",
2647
- authSkipValidation: false
2652
+ authStorage: "localStorage"
2648
2653
  };
2649
2654
  const config = { ...defaults, ...options };
2650
2655
  config.srcPath = this.resolvePath(config.srcPath, config.basePath);
@@ -2653,49 +2658,42 @@ var ViewLogicRouter = class {
2653
2658
  return config;
2654
2659
  }
2655
2660
  /**
2656
- * ํ†ตํ•ฉ ๊ฒฝ๋กœ ํ•ด๊ฒฐ - ์„œ๋ธŒํด๋” ๋ฐฐํฌ ๋ฐ basePath ์ง€์›
2661
+ * ๋‘ ๊ฒฝ๋กœ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์กฐํ•ฉ ๋ฐ ์ •๊ทœํ™” (๊ธฐ๋ณธ ์œ ํ‹ธ๋ฆฌํ‹ฐ)
2662
+ * @param {string} basePath - ๊ธฐ๋ณธ ๊ฒฝ๋กœ
2663
+ * @param {string} relativePath - ์ƒ๋Œ€ ๊ฒฝ๋กœ
2664
+ * @returns {string} ์กฐํ•ฉ๋œ ๊ฒฝ๋กœ (์˜ˆ: '/examples' + '/about' โ†’ '/examples/about')
2665
+ */
2666
+ combinePaths(basePath, relativePath) {
2667
+ if (!basePath || basePath === "/") {
2668
+ return relativePath.replace(/\/+/g, "/");
2669
+ }
2670
+ const cleanBase = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
2671
+ const cleanRelative = relativePath.startsWith("/") ? relativePath : `/${relativePath}`;
2672
+ const combined = `${cleanBase}${cleanRelative}`;
2673
+ return combined.replace(/\/+/g, "/");
2674
+ }
2675
+ /**
2676
+ * ์ƒ๋Œ€ ๊ฒฝ๋กœ๋ฅผ ์™„์ „ํ•œ ์ ˆ๋Œ€ URL๋กœ ๋ณ€ํ™˜ (ํŒŒ์ผ ์‹œ์Šคํ…œ ์ „์šฉ)
2677
+ * @param {string} path - ๋ณ€ํ™˜ํ•  ๊ฒฝ๋กœ
2678
+ * @param {string} basePath - ๊ธฐ๋ณธ ๊ฒฝ๋กœ (์˜ต์…˜)
2679
+ * @returns {string} ์™„์ „ํ•œ ์ ˆ๋Œ€ URL (์˜ˆ: 'http://localhost:3000/examples/about')
2657
2680
  */
2658
2681
  resolvePath(path, basePath = null) {
2682
+ if (basePath === null) {
2683
+ basePath = this.config?.basePath || "/";
2684
+ }
2659
2685
  const currentOrigin = window.location.origin;
2660
2686
  if (path.startsWith("http")) {
2661
2687
  return path;
2662
2688
  }
2663
2689
  if (path.startsWith("/")) {
2664
- if (basePath && basePath !== "/") {
2665
- const cleanBasePath = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
2666
- const cleanPath = path.startsWith("/") ? path : `/${path}`;
2667
- const fullPath = `${cleanBasePath}${cleanPath}`;
2668
- const fullUrl2 = `${currentOrigin}${fullPath}`;
2669
- return fullUrl2.replace(/([^:])\/{2,}/g, "$1/");
2670
- }
2671
- return `${currentOrigin}${path}`;
2690
+ const combinedPath = this.combinePaths(basePath, path);
2691
+ return `${currentOrigin}${combinedPath}`;
2672
2692
  }
2673
2693
  const currentPathname = window.location.pathname;
2674
2694
  const currentBase = currentPathname.endsWith("/") ? currentPathname : currentPathname.substring(0, currentPathname.lastIndexOf("/") + 1);
2675
- const resolvedPath = this.normalizePath(currentBase + path);
2676
- const fullUrl = `${currentOrigin}${resolvedPath}`;
2677
- return fullUrl.replace(/([^:])\/{2,}/g, "$1/");
2678
- }
2679
- /**
2680
- * URL ๊ฒฝ๋กœ ์ •๊ทœํ™” (์ด์ค‘ ์Šฌ๋ž˜์‹œ ์ œ๊ฑฐ ๋ฐ ../, ./ ์ฒ˜๋ฆฌ)
2681
- */
2682
- normalizePath(path) {
2683
- path = path.replace(/\/+/g, "/");
2684
- const parts = path.split("/").filter((part) => part !== "" && part !== ".");
2685
- const stack = [];
2686
- for (const part of parts) {
2687
- if (part === "..") {
2688
- if (stack.length > 0 && stack[stack.length - 1] !== "..") {
2689
- stack.pop();
2690
- } else if (!path.startsWith("/")) {
2691
- stack.push(part);
2692
- }
2693
- } else {
2694
- stack.push(part);
2695
- }
2696
- }
2697
- const normalized = "/" + stack.join("/");
2698
- return normalized === "/" ? "/" : normalized;
2695
+ const resolvedPath = this.combinePaths(currentBase, path);
2696
+ return `${currentOrigin}${resolvedPath}`;
2699
2697
  }
2700
2698
  /**
2701
2699
  * ๋กœ๊น… ๋ž˜ํผ ๋ฉ”์„œ๋“œ
@@ -2842,7 +2840,7 @@ var ViewLogicRouter = class {
2842
2840
  if (this.errorHandler) {
2843
2841
  await this.errorHandler.handleRouteError(routeName, error);
2844
2842
  } else {
2845
- console.error("[Router] No error handler available");
2843
+ console.error("[Router] Critical: No error handler available for route error:", error);
2846
2844
  }
2847
2845
  } finally {
2848
2846
  this.transitionInProgress = false;
@@ -2883,6 +2881,7 @@ var ViewLogicRouter = class {
2883
2881
  currentQuery: this.queryManager?.getQueryParams() || {}
2884
2882
  };
2885
2883
  newVueApp.mount(`#${newPageContainer.id}`);
2884
+ window.scrollTo(0, 0);
2886
2885
  requestAnimationFrame(() => {
2887
2886
  this.cleanupPreviousPages();
2888
2887
  this.transitionInProgress = false;
@@ -2936,31 +2935,17 @@ var ViewLogicRouter = class {
2936
2935
  updateURL(route, params = null) {
2937
2936
  const queryParams = params || this.queryManager?.getQueryParams() || {};
2938
2937
  const queryString = this.queryManager?.buildQueryString(queryParams) || "";
2939
- const buildURL = (route2, queryString2, isHash = true) => {
2940
- let base = route2 === "home" ? "/" : `/${route2}`;
2941
- if (!isHash && this.config.basePath && this.config.basePath !== "/") {
2942
- base = `${this.config.basePath}${base}`;
2943
- }
2944
- const url = queryString2 ? `${base}?${queryString2}` : base;
2945
- return isHash ? `#${url}` : url;
2946
- };
2938
+ let base = route === "home" ? "/" : `/${route}`;
2947
2939
  if (this.config.mode === "hash") {
2948
- const newHash = buildURL(route, queryString);
2940
+ const url = queryString ? `${base}?${queryString}` : base;
2941
+ const newHash = `#${url}`;
2949
2942
  if (window.location.hash !== newHash) {
2950
2943
  window.location.hash = newHash;
2951
2944
  }
2952
2945
  } else {
2953
- const newPath = buildURL(route, queryString, false);
2954
- let expectedPath = route === "home" ? "/" : `/${route}`;
2955
- if (this.config.basePath && this.config.basePath !== "/") {
2956
- expectedPath = `${this.config.basePath}${expectedPath}`;
2957
- }
2958
- const isSameRoute = window.location.pathname === expectedPath;
2959
- if (isSameRoute) {
2960
- window.history.replaceState({}, "", newPath);
2961
- } else {
2962
- window.history.pushState({}, "", newPath);
2963
- }
2946
+ base = this.combinePaths(this.config.basePath, base);
2947
+ const url = queryString ? `${base}?${queryString}` : base;
2948
+ window.history.pushState({}, "", url);
2964
2949
  this.handleRouteChange();
2965
2950
  }
2966
2951
  }