what-router 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/index.js +26 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "what-router",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "What Framework - File-based & programmatic router with View Transitions",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -26,7 +26,7 @@
26
26
  "author": "",
27
27
  "license": "MIT",
28
28
  "peerDependencies": {
29
- "what-core": "^0.2.0"
29
+ "what-core": "^0.3.0"
30
30
  },
31
31
  "repository": {
32
32
  "type": "git",
package/src/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // Production-grade file-based routing with nested layouts, loading states,
3
3
  // route groups, view transitions, and middleware.
4
4
 
5
- import { signal, effect, computed, batch, h } from 'what-core';
5
+ import { signal, effect, computed, batch, h, ErrorBoundary } from 'what-core';
6
6
 
7
7
  // --- Route State (global singleton) ---
8
8
 
@@ -187,6 +187,24 @@ export function Router({ routes, fallback, globalLayout }) {
187
187
  });
188
188
 
189
189
  const { route: r, params } = matched;
190
+ const queryObj = parseQuery(search);
191
+
192
+ // Run middleware (sync only — async middleware should use asyncGuard)
193
+ if (r.middleware && r.middleware.length > 0) {
194
+ for (const mw of r.middleware) {
195
+ const result = mw({ path, params, query: queryObj, route: r });
196
+ if (result === false) {
197
+ // Middleware rejected — show fallback
198
+ if (fallback) return h(fallback, {});
199
+ return h('div', { class: 'what-403' }, h('h1', null, '403'), h('p', null, 'Access denied'));
200
+ }
201
+ if (typeof result === 'string') {
202
+ // Middleware returned a redirect path
203
+ navigate(result, { replace: true });
204
+ return null;
205
+ }
206
+ }
207
+ }
190
208
 
191
209
  // Build element with loading state support
192
210
  let element;
@@ -196,15 +214,20 @@ export function Router({ routes, fallback, globalLayout }) {
196
214
  } else {
197
215
  element = h(r.component, {
198
216
  params,
199
- query: parseQuery(search),
217
+ query: queryObj,
200
218
  route: r,
201
219
  });
202
220
  }
203
221
 
222
+ // Wrap with per-route error boundary if specified
223
+ if (r.error) {
224
+ element = h(ErrorBoundary, { fallback: r.error }, element);
225
+ }
226
+
204
227
  // Wrap with nested layouts (innermost to outermost)
205
228
  const layouts = buildLayoutChain(r, routes);
206
229
  for (const Layout of layouts.reverse()) {
207
- element = h(Layout, { params, query: parseQuery(search) }, element);
230
+ element = h(Layout, { params, query: queryObj }, element);
208
231
  }
209
232
 
210
233
  // Global layout wrapper