white-label-router 1.1.2 → 5.0.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.
package/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 bshack
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,361 +1,283 @@
1
1
  # white-label-router
2
2
 
3
- A simple ES6 JS router based on the history api and pushstate.
3
+ > Turn URLs into application intent without hiding the web platform.
4
4
 
5
- Learn more about ES6 classes here:
5
+ `white-label-router` is a framework-independent TypeScript router for browser and server applications. It progressively enhances real links with the History API in the browser and dispatches explicit request URLs on the server through the same matching, guard, lifecycle, query, focus, and mediator contracts.
6
6
 
7
- https://babeljs.io/docs/learn-es2015/
7
+ [Documentation](https://whitelabeljs.org/docs/router/) · [API reference](https://whitelabeljs.org/api/#router) · [Demo site](https://whitelabeljs.org/)
8
8
 
9
- ## Install
10
-
11
- Install the node module:
9
+ **Responsibility:** translate navigation into application intent. Nothing more.
12
10
 
13
- ```
14
- npm install white-label-router --save
15
- ```
11
+ ## Why it exists
16
12
 
17
- ## Import
13
+ White Label keeps URLs, links, history, and server requests visible rather than replacing them with a proprietary navigation model. Router adds the application boundary around those platform primitives while preserving normal browser behavior whenever enhancement does not apply.
18
14
 
19
- ```
20
- import Router from 'white-label-router';
21
- ```
15
+ Use it independently or compose it with the rest of White Label:
22
16
 
17
+ - [`white-label-mediator`](https://github.com/bshack/white-label-mediator) can publish `router:navigate` intent.
18
+ - [`white-label-model`](https://github.com/bshack/white-label-model) can own state changed by a route.
19
+ - [`white-label-view`](https://github.com/bshack/white-label-view) can own the rendering lifecycle started by a route.
20
+ - [`generator-white-label`](https://github.com/bshack/white-label) demonstrates the complete composition.
23
21
 
24
- ## Defining Routes
22
+ The package has no runtime dependency on the other White Label packages.
25
23
 
26
- The most simple way simply executes any function you define:
24
+ ## Requirements
27
25
 
28
- ```
29
- const MyRoute = class extends Router {
30
- constructor() {
31
- super();
32
- this.routes = {
33
- defaultRoute: (scope, locationData) => {
34
- //here you would put any view specific logic for the defaultRoute
35
- window.console.log('the defaultRoute executed');
36
- },
37
- '/page2': (scope, locationData) => {
38
- //here you would put any view specific logic for the page2 route
39
- window.console.log('the page2 route executed');
40
- }
41
- };
42
- }
43
- };
44
- ```
26
+ - Node.js `^22.18.0` or `>=24.11.0` for installation, development, and server execution.
27
+ - npm, Yarn, and pnpm are supported for installation; see [`PACKAGE_MANAGERS.md`](PACKAGE_MANAGERS.md).
28
+ - Browser History API, location, and standard DOM events only when using browser navigation behavior.
29
+ - A directly requestable server route for every public browser route so enhanced links remain meaningful without JavaScript.
45
30
 
46
- or you can also define initialize and destroy functions in your view which will be automatically called as the user navigates your application:
31
+ ## Install
47
32
 
48
- ```
49
- const MyRoute = class extends Router {
50
- constructor() {
51
- super();
52
- this.routes = {
53
- defaultRoute: {
54
- view: {
55
- initialize: (scope, locationData) => {
56
- window.console.log('the defaultRoute initialized');
57
- },
58
- destroy: (scope, locationData) => {
59
- window.console.log('the defaultRoute has been destroyed');
60
- }
61
- }
62
- },
63
- '/page2': {
64
- view: {
65
- initialize: (scope, locationData) => {
66
- window.console.log('the page2 initialized');
67
- },
68
- destroy: (scope, locationData) => {
69
- window.console.log('the page2 has been destroyed');
70
- }
71
- }
72
- }
73
- };
74
- }
75
- };
33
+ ```sh
34
+ npm install white-label-router
35
+ # or: yarn add white-label-router
36
+ # or: pnpm add white-label-router
76
37
  ```
77
38
 
78
- You have some additional options when using the view object approach. They include the ability to set the page title for a route and also do security check before a route's view is initialized at the router level:
39
+ The same entrypoint is used in browsers and servers:
79
40
 
80
- ```
81
- const MyRoute = class extends Router {
82
- constructor() {
83
- super();
84
- this.routes = {
85
- defaultRoute: {
86
- title: 'Home',
87
- view: {
88
- initialize: (scope, locationData) => {
89
- window.console.log('the defaultRoute initialized');
90
- },
91
- destroy: (scope, locationData) => {
92
- window.console.log('the defaultRoute has been destroyed');
93
- }
94
- }
95
- },
96
- '/page2': {
97
- title: 'Page 2',
98
- view: {
99
- initialize: (scope, locationData) => {
100
- window.console.log('the page2 initialized');
101
- },
102
- destroy: (scope, locationData) => {
103
- window.console.log('the page2 has been destroyed');
104
- }
105
- },
106
- secure: this.isSecure
107
- }
108
- };
109
- }
110
- isSecure (scope, locationData) => {
111
- if (someCookieIsValid) {
112
- return true;
113
- } else {
114
- return false;
115
- }
116
- }
117
- };
41
+ ```js
42
+ import Router from 'white-label-router';
118
43
  ```
119
44
 
120
- NOTE: routes are matched by checking if the beginning of the url path name string matches a route. For the example above the route '/page2' would be executed for both path names '/page2' and '/page23/232'.
45
+ ## One route contract, two runtimes
121
46
 
122
- ## Scope
47
+ ### Browser
123
48
 
124
- Optionally you and provide a DOM element to be the scope of the router. That DOM object will then be passed into all your routes as they are executed. If you do not provide a scope then it will be passed in as null into your views. To do so you would like this:
49
+ Omit the URL to dispatch the current browser location and attach browser navigation listeners:
125
50
 
51
+ ```js
52
+ const router = new Router();
53
+ router.routes = {
54
+ '/products': (_scope, location) => console.log(location.data.url),
55
+ defaultRoute: () => true
56
+ };
57
+
58
+ // initialize() dispatches the current URL and returns the router for chaining.
59
+ router.initialize();
126
60
  ```
127
- const MyRoute = class extends Router {
128
- constructor() {
129
- super();
130
61
 
131
- // the container element where all views will be placed
132
- this.scope = document.querySelector('body');
62
+ ### Server
133
63
 
134
- this.routes = {
135
- defaultRoute: (scope, locationData) => {
136
- //here you would put any view specific logic for the defaultRoute
137
- window.console.log('the defaultRoute executed');
138
- },
139
- '/page2': (scope, locationData) => {
140
- //here you would put any view specific logic for the page2 route
141
- window.console.log('the page2 route executed');
142
- }
143
- };
64
+ Pass the request URL explicitly. No `window` or `document` is required:
144
65
 
145
- }
66
+ ```js
67
+ const router = new Router();
68
+ router.routes = {
69
+ '/products': (_scope, location) => console.log(location.data.url),
70
+ defaultRoute: () => true
146
71
  };
72
+ router.initialize('/products/42?color=blue');
147
73
  ```
148
74
 
149
- ## Instantiate
75
+ Browser-only history, click interception, focus, and document-title effects are skipped on the server. Scope mutable routing state per request when appropriate.
150
76
 
151
- ```
152
- const myRouter = new MyRouter();
77
+ ## Serverless and function runtimes
153
78
 
154
- myRouter.initialize();
79
+ Pass the incoming request URL explicitly when Router runs inside a serverless function. The server path uses the same matching, query parsing, guards, and route lifecycle without requiring `window` or `document`.
80
+
81
+ ```js
82
+ const requestUrl = new URL(request.url);
83
+ const router = new Router();
84
+ router.routes = routes;
85
+ router.initialize(`${requestUrl.pathname}${requestUrl.search}`);
155
86
  ```
156
87
 
157
- ## HTML Linking To Routes
88
+ Create a request-scoped Router when its location state, mediator, route lifecycle, or other mutable configuration belongs to one invocation. Warm function processes may serve sequential or overlapping requests, so sharing one mutable Router can mix location/lifecycle state unless that process-wide lifetime is intentional.
158
89
 
159
- you can make any anchor tigger a specified route by simply setting the href attribute to your route path and adding the attribute 'data-pushstate'.
90
+ Router handles **application routing inside the invocation**. It does not replace API Gateway routes, CDN routing, Vercel/Netlify/Cloudflare route configuration, load balancing, authentication infrastructure, or other cloud request plumbing.
160
91
 
161
- ```
162
- <a href="/page2" data-pushstate>take me to page2</a>
163
- ```
92
+ The package currently documents Node.js as its supported server runtime. Its DOM-free server path uses standard URL APIs, but that is not a blanket compatibility claim for every edge provider; verify the actual target runtime before deployment.
164
93
 
165
- ## Navigate
94
+ ## Progressive enhancement first
166
95
 
167
- you can also trigger navigation to a route with the navigate method
96
+ Public navigation should remain a real link:
168
97
 
169
- ```
170
- myRouter.navigate('/page2');
98
+ ```html
99
+ <a href="/products/42" data-pushstate>View product 42</a>
171
100
  ```
172
101
 
173
- ## Mediator
102
+ `data-pushstate` opts the link into client-side enhancement. Links without it retain native behavior. Modified clicks, non-left clicks, downloads, alternate targets, and cross-origin URLs also remain native.
174
103
 
175
- Optionally you can use a mediator, such as White Label Mediator, with the router. To do so you would like this:
104
+ This preserves keyboard behavior, context menus, no-JavaScript navigation, and crawler discovery. Public routes should have directly requestable URLs that return meaningful HTML and appropriate title, description, canonical, and robots metadata.
176
105
 
177
- ```
178
- const MyRoute = class extends Router {
179
- constructor() {
180
- super();
106
+ ## Define routes
181
107
 
182
- // the container element where all views will be placed
183
- this.scope = document.querySelector('body');
108
+ A route can be a function:
184
109
 
185
- this.mediator = myMediator;
110
+ ```js
111
+ router.routes = {
112
+ '/help': (scope, location) => {
113
+ scope.textContent = `Help page: ${location.url}`;
114
+ }
115
+ };
116
+ ```
186
117
 
187
- this.routes = {
188
- defaultRoute: (scope, locationData) => {
189
- //here you would put any view specific logic for the defaultRoute
190
- window.console.log('the defaultRoute executed');
118
+ Or an object describing route lifecycle:
119
+
120
+ ```js
121
+ router.routes = {
122
+ '/orders': {
123
+ title: 'Orders',
124
+ focus: '#orders-title',
125
+ secure(scope, location) {
126
+ // Guards must return exactly true to allow navigation.
127
+ return Boolean(window.currentUser);
128
+ },
129
+ view: {
130
+ initialize(scope, location) {
131
+ scope.textContent = 'Order history';
191
132
  },
192
- '/page2': (scope, locationData) => {
193
- //here you would put any view specific logic for the page2 route
194
- window.console.log('the page2 route executed');
133
+ destroy(scope, nextLocation) {
134
+ scope.replaceChildren();
195
135
  }
196
- };
197
-
136
+ }
198
137
  }
199
138
  };
200
139
  ```
201
140
 
202
- Then anywhere else in the application you want to trigger the router to navigate you could do so like this:
203
-
204
- ```
205
- myMediator.emit('router:navigate', {
206
- url: '/authentication',
207
- message: 'Session expired, please login again.'
208
- });
209
- ```
141
+ `secure()` must return exactly `true` to allow navigation. On a successful route change, the previous route's `destroy()` runs before the next route's `initialize()`.
210
142
 
211
- ## Scope
143
+ ## Matching
212
144
 
213
- Optionally you and provide a DOM element to be the scope of the router. That DOM object will then be passed into all your routes as they are executed. To do so you would like this:
145
+ Routes match complete path boundaries. `/products` matches `/products` and `/products/42`, but not `/products-old`.
214
146
 
215
- ```
216
- const MyRoute = class extends Router {
217
- constructor() {
218
- super();
147
+ When multiple route prefixes match, Router selects the **longest matching route**, so specific routes win without depending on object insertion order:
219
148
 
220
- // the container element where all views will be placed
221
- this.scope = document.querySelector('body');
222
-
223
- this.routes = {
224
- defaultRoute: (scope, locationData) => {
225
- //here you would put any view specific logic for the defaultRoute
226
- window.console.log('the defaultRoute executed');
227
- },
228
- '/page2': (scope, locationData) => {
229
- //here you would put any view specific logic for the page2 route
230
- window.console.log('the page2 route executed');
231
- }
232
- };
233
-
234
- }
149
+ ```js
150
+ router.routes = {
151
+ '/products': productsRoute,
152
+ '/products/sale': saleRoute,
153
+ defaultRoute
235
154
  };
236
155
  ```
237
156
 
238
- ## Passing Data
157
+ `/products/sale` selects `saleRoute` even though `/products` was defined first. When no prefix matches, `defaultRoute` runs if configured.
239
158
 
240
- The router passes in a location data object to the route that is being executed. Here is an example object passed:
159
+ ## Location contract
241
160
 
242
- ```
161
+ Routes receive the configured `scope` and a location object:
162
+
163
+ ```js
243
164
  {
244
- url: ['/user'],
165
+ url: '/products/42?color=blue',
245
166
  data: {
246
- url: [],
247
- mediator: {},
248
- query: {}
167
+ url: ['42'],
168
+ mediator: {source: 'featured-products'},
169
+ query: {color: 'blue'}
249
170
  }
250
171
  }
251
172
  ```
252
173
 
253
- 'data.url' is an array of values parsed from the url being requested. For Example if the url was '/user/fred' and we defined a route for '/user' then data object passed into the '/user' route would be the following:
174
+ `data.url` contains path segments after the matched prefix, `data.query` contains parsed query values, and `data.mediator` contains navigation data supplied programmatically or through the mediator. Values are URI-decoded with standard WHATWG URL APIs; applications must still validate untrusted values.
254
175
 
255
- ```
256
- {
257
- url: ['/user/fred'],
258
- data: {
259
- url: ['fred'],
260
- mediator: {},
261
- query: {}
262
- }
263
- }
264
- ```
176
+ ## Programmatic navigation
265
177
 
266
- 'data.query' is an object of values parsed from the url query string. For Example if the url was '/user?name=fred' and we defined a route for '/user' then data object passed into the '/user' route would be the following:
178
+ ```js
179
+ const result = router.navigate('/products/42', {
180
+ source: 'featured-products'
181
+ });
267
182
 
268
- ```
269
- {
270
- url: ['/user?name=fred'],
271
- data: {
272
- url: [],
273
- mediator: {},
274
- query: {
275
- name: 'fred'
276
- }
277
- }
278
- }
183
+ // `result` is the router on success or false when navigation is rejected.
279
184
  ```
280
185
 
281
- 'data.mediator' is an object of values parsed through the optional mediator. For Example if this was emitted through the mediator:
186
+ In browsers, successful navigation updates history unless the call represents `popstate`. On servers it dispatches without History API effects.
282
187
 
283
- ```
284
- myMediator.emit('router:navigate', {
285
- url: '/authentication',
286
- message: 'Session expired, please login again.'
287
- });
288
- ```
188
+ Calling `navigate()` without a URL dispatches the current browser URL. In a non-browser runtime the safe default is `/`; server applications should normally supply the request URL explicitly.
289
189
 
290
- Then the location data passed in to the '/authentication' route would be the following:
190
+ ## Mediator integration
291
191
 
292
- ```
293
- {
294
- url: ['/authentication'],
295
- data: {
296
- url: [],
297
- mediator: {
298
- url: '/authentication',
299
- message: 'Session expired, please login again.'
300
- }
301
- }
302
- }
303
- ```
192
+ Assign any EventEmitter-compatible mediator that provides `on()` and `removeListener()`:
304
193
 
305
- ## Let's look at an example:
194
+ ```js
195
+ import Mediator from 'white-label-mediator';
306
196
 
307
- import the module
197
+ const mediator = new Mediator();
198
+ const router = new Router();
308
199
 
200
+ router.mediator = mediator;
201
+ router.initialize();
202
+
203
+ mediator.emit('router:navigate', {
204
+ url: '/account',
205
+ reason: 'Session refreshed'
206
+ });
309
207
  ```
310
- import Router from 'white-label-router';
208
+
209
+ The complete event object becomes `location.data.mediator`. `destroy()` removes listeners owned by Router. Repeated listener initialization is idempotent.
210
+
211
+ ## Public API
212
+
213
+ | Member | Behavior | Returns |
214
+ | --- | --- | --- |
215
+ | `routes` | Ordered route table of functions or lifecycle route objects. | Configuration property; not a method. |
216
+ | `scope` | Application scope passed to route callbacks. | Configuration property; not a method. |
217
+ | `mediator` | Optional EventEmitter-compatible source for `router:navigate`. | Configuration property; not a method. |
218
+ | `initialize(url?)` | Dispatch the browser URL or an explicit server URL and attach applicable listeners. | The same `Router` instance. |
219
+ | `navigate(url?, data?, isPopState?)` | Match and run a route; update browser history when appropriate. | The same `Router` instance on success; `false` for cross-origin browser URLs, rejected guards, or routes without runnable view behavior. |
220
+ | `addListeners()` | Attach browser and optional mediator listeners once. | The same `Router` instance. |
221
+ | `removeListeners()` | Release listeners owned by this router. | The same `Router` instance. |
222
+ | `destroy()` | Release routing listeners. | The same `Router` instance after cleanup. |
223
+ | `parseQueryString(query)` | Decode a query string using `URLSearchParams`. | A plain object containing the last value for each query key. |
224
+ | `setLocationData(data?)` | Rebuild the current route location payload. | `undefined`; updates `locationData` in place. |
225
+ | `applyPageContext(route)` | Update route title/focus context when applicable. | The same `Router` instance. |
226
+ | `eventPushStateClick(event)` | Handle an eligible browser push-state click. | The same `Router` instance after handled navigation; `true` when native/default handling should continue. |
227
+ | `eventPopState()` | Dispatch the current browser history location. | The same `Router` instance. |
228
+
229
+ ## Title and focus
230
+
231
+ Object routes can define browser title and focus behavior:
232
+
233
+ ```js
234
+ router.routes = {
235
+ '/account': {
236
+ title: 'Account',
237
+ focus: '#account-title',
238
+ view: renderAccount
239
+ }
240
+ };
311
241
  ```
312
242
 
313
- extend the router
243
+ The default focus selector is `main h1`. Set `focus: false` for an in-page refinement that should preserve current focus. Server runtimes retain `pageTitle` as route state but do not mutate a document or focus target.
314
244
 
315
- ```
316
- const myRouter = class extends Router {
317
- // this is the constructor. This executed whenever the view is instantiated.
318
- constructor() {
245
+ ## Browser history behavior
319
246
 
320
- super();
247
+ Initialization dispatches the current URL without adding a duplicate history entry. Back/forward navigation reads `window.location`—including path, query, and hash—even when history state is null or belongs to another application. History state is not treated as the authoritative URL.
321
248
 
322
- // the container element where all views will be placed
323
- this.scope = document.querySelector('body');
249
+ ## TypeScript
324
250
 
325
- this.routes = {
326
- defaultRoute: (scope, locationData) => {
327
- //here you would put any view specific logic for the defaultRoute
328
- window.console.log('the defaultRoute executed');
329
- },
330
- '/page2': (scope, locationData) => {
331
- //here you would put any view specific logic for the page2 route
332
- window.console.log('the page2 route executed');
333
- }
334
- };
335
-
336
- }
251
+ Implementation uses strict TypeScript and emits JavaScript, source maps, and declarations into `dist`.
252
+
253
+ ```ts
254
+ const router = new Router();
255
+ const greeting: Router.Route = (scope, location) => {
256
+ console.log(location.data.query.name);
337
257
  };
338
258
 
259
+ router.routes['/hello'] = greeting;
260
+ router.initialize();
339
261
  ```
340
262
 
341
- instantiate your router
263
+ `Router.Route`, `Router.Location`, `Router.Navigation`, and `Router.Handler` expose the supported contracts. Browser DOM types are present because the same class supports browser scopes and events; server hosts do not need DOM globals at runtime.
342
264
 
343
- ```
344
- const myRouter = new MyRoute();
345
- ```
346
-
347
- initialize your router
265
+ ## Development
348
266
 
349
- ```
350
- myRouter.initialize();
267
+ ```sh
268
+ npm ci --ignore-scripts
269
+ npm run lint
270
+ npm run typecheck
271
+ npm test
272
+ npm run coverage
273
+ npm run audit
274
+ npm pack --dry-run
351
275
  ```
352
276
 
353
- navigate to '/page2'
277
+ Tests cover browser behavior, DOM-free server routing, and parity of the shared route contract. Coverage enforces 100% statements, branches, functions, and lines per implementation file. CI builds authored source, uploads generated artifacts for inspection, audits dependencies, packs the package, and verifies the packed public API across npm, Yarn, and pnpm.
354
278
 
355
- ```
356
- myRouter.navigate('/page2');
357
- ```
279
+ Edit `src/*.ts` and regenerate `dist`; do not edit generated files directly.
358
280
 
359
- In the example above we have set up two routes. The first route 'defaultRoute' is a catch all route. If no other routes match the specified url path this is the route that will be executed. In this example the defaultRoute would be executed for 'http://example.com' or 'http://example.com/home', but not 'http://example.com/page2'.
281
+ ## Design boundary
360
282
 
361
- The second defined route 'page2' will only be executed when the specified url path starts with '/page2', or for example 'http://example.com/page2'.
283
+ Router owns URL-to-intent translation. It intentionally does not own application state, rendering, data loading, authentication policy, or server infrastructure. Real links and server URLs remain the foundation; Router enhances them instead of replacing them.
@@ -0,0 +1,89 @@
1
+ /** Navigation payload, including caller-defined metadata. */
2
+ interface NavigationData {
3
+ url?: string;
4
+ [key: string]: unknown;
5
+ }
6
+ /** URL-derived values supplied to route handlers. */
7
+ interface LocationData {
8
+ url: string;
9
+ data: {
10
+ url: string[];
11
+ mediator: NavigationData | undefined;
12
+ query: Record<string, string>;
13
+ };
14
+ }
15
+ type RouteHandler = (scope: Element | null, location: LocationData) => unknown;
16
+ /** An object route can own a function or a view lifecycle. */
17
+ interface RouteObject {
18
+ title?: string;
19
+ focus?: string | false;
20
+ secure?: RouteHandler;
21
+ view?: RouteHandler | {
22
+ initialize?: RouteHandler;
23
+ destroy?: RouteHandler;
24
+ };
25
+ }
26
+ type Route = RouteHandler | RouteObject;
27
+ /** Minimal event-bus contract required by the router. */
28
+ interface NavigationMediator {
29
+ on(event: string, callback: (data?: NavigationData) => unknown): unknown;
30
+ removeListener(event: string, callback: (data?: NavigationData) => unknown): unknown;
31
+ }
32
+ /** History API router that also dispatches request URLs in non-browser runtimes. */
33
+ declare class Router {
34
+ routes: Record<string, Route>;
35
+ url: string;
36
+ route: string | null;
37
+ scope: Element | null;
38
+ previousRoute: string | null;
39
+ pageTitle: string | null;
40
+ mediator: NavigationMediator | false;
41
+ boundPushStateClick: (event: MouseEvent) => unknown;
42
+ boundPopState: (event: PopStateEvent) => unknown;
43
+ boundMediatorNavigate: (data?: NavigationData) => unknown;
44
+ listenersInitialized: boolean;
45
+ locationData: LocationData;
46
+ /** Create an instance with its own state and listener references. */
47
+ constructor();
48
+ /** True when browser navigation APIs are available. */
49
+ private isBrowserRuntime;
50
+ /** Stable base URL for WHATWG URL parsing in browser and server runtimes. */
51
+ private getOrigin;
52
+ /** Read the authoritative browser URL, or retain the supplied server URL. */
53
+ private getCurrentUrl;
54
+ /** Normalize browser navigation to a same-origin path, query, and hash. */
55
+ private normalizeBrowserUrl;
56
+ /**
57
+ * Start this instance and return it for lifecycle chaining.
58
+ * In a browser the URL is optional and defaults to window.location. On a server pass the request URL.
59
+ */
60
+ initialize(url?: string): this;
61
+ /** Register browser and optional mediator handlers once. */
62
+ addListeners(): this;
63
+ /** Release owned state and listeners so the instance can leave the application lifecycle. */
64
+ destroy(): this;
65
+ /** Release listeners owned by this instance; subclasses may extend the lifecycle hook. */
66
+ removeListeners(): this;
67
+ /** Intercept eligible same-origin push-state links while preserving normal browser actions. */
68
+ eventPushStateClick(e: MouseEvent): true | this;
69
+ /** Restore browser history state without adding a new history entry. */
70
+ eventPopState(): this;
71
+ /** Decode URL query parameters, keeping the last value for duplicate keys. */
72
+ parseQueryString(queryString: string): {
73
+ [k: string]: string;
74
+ };
75
+ /** Build decoded path, query, and mediator data for the selected route. */
76
+ setLocationData(mediatorData?: NavigationData): void;
77
+ /** Update page context after a route renders. DOM effects are browser-only. */
78
+ applyPageContext(route: Route): this;
79
+ /** Select a route, enforce its guard, transition view lifecycles, and update browser history when available. */
80
+ navigate(url?: string, mediatorData?: NavigationData, isPopState?: boolean): false | this;
81
+ }
82
+ /** Public route configuration and navigation payload types. */
83
+ declare namespace Router {
84
+ type Handler = RouteHandler;
85
+ type Route = RouteHandler | RouteObject;
86
+ type Location = LocationData;
87
+ type Navigation = NavigationData;
88
+ }
89
+ export = Router;