@tinkoff/router 0.1.63 → 0.1.67

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
@@ -66,8 +66,25 @@ export const myGuard: NavigationGuard = async ({ to }) => {
66
66
 
67
67
  // if nothing is returned, the transition will be performed as usual
68
68
  };
69
+
70
+ router.registerGuard(myGuard);
69
71
  ```
70
72
 
73
+ #### Rules
74
+
75
+ - guards are asynchronous and it execution will be awaited inside routing
76
+ - all guards are running in parallel and they are all awaited
77
+ - if several guars return something then the result from a guard that was registered early will be used
78
+
79
+ #### Possible result
80
+
81
+ The behaviour of routing depends on the result of executing guards functions and there result might be next:
82
+
83
+ - if all of the guards returns `undefined` than navigation will continue executing
84
+ - if any of the guards returns `false` than navigation is getting blocked and next action differs on server and client
85
+ - if any of the guards returns `string` it is considered as url to which redirect should be happen
86
+ - if any of the guards returns `NavigateOptions` interface, `url` property from it is considered as url to which redirect should be happen
87
+
71
88
  ### Transitions hooks
72
89
 
73
90
  Transition hooks allow you to perform your asynchronous actions at different stages of the transition.
@@ -78,8 +95,27 @@ import { NavigationHook } from '@tinkoff/router';
78
95
  export const myHook: NavigationHook = async ({ from, to, url, fromUrl }) => {
79
96
  console.log(`navigating from ${from} to route ${to}`);
80
97
  };
98
+
99
+ router.registerHook('beforeNavigate', myHook);
81
100
  ```
82
101
 
102
+ #### Rules
103
+
104
+ - all hooks from the same event are running in parallel
105
+ - most of the hooks are asynchronous and are awaited inside router
106
+ - if some error happens when running hook it will be logged to console but wont affect navigation (except for the `beforeResolve` hook - error for it will be rethrown)
107
+
108
+ #### List of available hooks
109
+
110
+ Async hooks:
111
+
112
+ - [navigate hooks](#navigate-hooks) - asynchronous hooks only for navigate calls
113
+ - [updateCurrentRoute hooks](#updatecurrentroute-hooks) - asynchronous hooks only for updateCurrentRoute calls
114
+
115
+ Sync hooks:
116
+
117
+ - `change` - runs when any of changes to current route\url happens
118
+
83
119
  ## API
84
120
 
85
121
  ### Getting data about the current route or url
@@ -102,12 +138,20 @@ router.navigate('/test');
102
138
  router.navigate({ url: './test', query: { a: '1' } });
103
139
  ```
104
140
 
105
- Transition hooks:
141
+ ##### navigate hooks
106
142
 
107
143
  - beforeResolve
108
144
  - beforeNavigate
109
145
  - afterNavigate
110
146
 
147
+ ##### navigate workflow
148
+
149
+ 1. `beforeResolve` hook
150
+ 2. [guards](#router-guards)
151
+ 3. `beforeNavigate`
152
+ 4. `change`
153
+ 5. `afterNavigate`
154
+
111
155
  #### updateCurrentRoute
112
156
 
113
157
  The transition is based on the current route (therefore this method cannot be called on the server) and allows you to simply update some data for the current page
@@ -117,11 +161,17 @@ router.updateCurrentRoute({ params: { id: 'abc' } });
117
161
  router.updateCurrentRoute({ query: { a: '1' } });
118
162
  ```
119
163
 
120
- Hooks:
164
+ ##### updateCurrentRoute hooks
121
165
 
122
166
  - beforeUpdateCurrent
123
167
  - afterUpdateCurrent
124
168
 
169
+ ##### updateCurrentRoute workflow
170
+
171
+ 1. `beforeUpdateCurrent`
172
+ 2. `change`
173
+ 3. `afterUpdateCurrent`
174
+
125
175
  ### Working with query
126
176
 
127
177
  #### query option
@@ -161,6 +211,11 @@ router.updateCurrentRoute({ query: { a: undefined, c: 'c' }, preserveQuery: true
161
211
  router.getCurrentUrl().query; // { b: 'b', c: 'c' }
162
212
  ```
163
213
 
214
+ ### Constructor options
215
+
216
+ - `trailingSlash` - do router should force all urls to end with slash. If `true` - force trailing slash for every path, `false` - force no trailing slash, `undefined` - trailing slash is specified by request and both trailing and not trailing slashes are used. By default value if `undefined`
217
+ - `mergeSlashes` - replace several consecutive slashes by single slashes (slashes after protocol are still be with `//` after protocol name). By default is `false` - no merge for slashes.
218
+
164
219
  ### Integration with React
165
220
 
166
221
  Library has some useful React hooks and components for working with routing
@@ -229,3 +284,26 @@ export const WrapLink = () => {
229
284
  return <Link url="/test/">Click me</Link>;
230
285
  };
231
286
  ```
287
+
288
+ ## How to
289
+
290
+ ### Load route config from external api
291
+
292
+ Use [transition hook](#transitions-hooks) `beforeResolve` and load routes config based on url.
293
+
294
+ ```ts
295
+ router.registerHook('beforeResolve', async (navigation) => {
296
+ const route = await routeResolve(navigation);
297
+
298
+ if (route) {
299
+ router.addRoute(routeTransform(route));
300
+ }
301
+ });
302
+ ```
303
+
304
+ ### App behind proxy
305
+
306
+ Router doesn't support proxy setup directly. But proxy still can be used with some limitations:
307
+
308
+ - setup proxy server to pass requests to app with rewriting request and response paths. (E.g. for [nginx](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect))
309
+ - it wont work as expected on spa navigation on client, so only option in this case is use the `NoSpaRouter`
package/lib/index.es.js CHANGED
@@ -668,9 +668,11 @@ class RouteTree {
668
668
 
669
669
  class Router extends AbstractRouter {
670
670
  constructor(options) {
671
+ var _a;
671
672
  super(options);
672
673
  this.blocked = false;
673
674
  this.tree = new RouteTree(options.routes);
675
+ this.defaultRedirectCode = (_a = options.defaultRedirectCode) !== null && _a !== void 0 ? _a : 308;
674
676
  this.history = new ServerHistory();
675
677
  }
676
678
  async dehydrate() {
@@ -713,13 +715,13 @@ class Router extends AbstractRouter {
713
715
  normalizePathname(pathname) {
714
716
  const normalized = super.normalizePathname(pathname);
715
717
  if (normalized !== pathname) {
716
- this.redirectCode = 308;
718
+ this.redirectCode = this.defaultRedirectCode;
717
719
  }
718
720
  return normalized;
719
721
  }
720
722
  resolveUrl(options) {
721
723
  if (options.url && isInvalidUrl(options.url)) {
722
- this.redirectCode = 308;
724
+ this.redirectCode = this.defaultRedirectCode;
723
725
  }
724
726
  return super.resolveUrl(options);
725
727
  }
package/lib/index.js CHANGED
@@ -684,9 +684,11 @@ class RouteTree {
684
684
 
685
685
  class Router extends AbstractRouter {
686
686
  constructor(options) {
687
+ var _a;
687
688
  super(options);
688
689
  this.blocked = false;
689
690
  this.tree = new RouteTree(options.routes);
691
+ this.defaultRedirectCode = (_a = options.defaultRedirectCode) !== null && _a !== void 0 ? _a : 308;
690
692
  this.history = new ServerHistory();
691
693
  }
692
694
  async dehydrate() {
@@ -729,13 +731,13 @@ class Router extends AbstractRouter {
729
731
  normalizePathname(pathname) {
730
732
  const normalized = super.normalizePathname(pathname);
731
733
  if (normalized !== pathname) {
732
- this.redirectCode = 308;
734
+ this.redirectCode = this.defaultRedirectCode;
733
735
  }
734
736
  return normalized;
735
737
  }
736
738
  resolveUrl(options) {
737
739
  if (options.url && url.isInvalidUrl(options.url)) {
738
- this.redirectCode = 308;
740
+ this.redirectCode = this.defaultRedirectCode;
739
741
  }
740
742
  return super.resolveUrl(options);
741
743
  }
@@ -16,6 +16,7 @@ export interface Options {
16
16
  afterUpdateCurrent?: NavigationHook[];
17
17
  guards?: NavigationGuard[];
18
18
  onChange?: NavigationSyncHook[];
19
+ defaultRedirectCode?: number;
19
20
  }
20
21
  interface InternalOptions {
21
22
  history?: boolean;
@@ -1,14 +1,11 @@
1
1
  import type { Options } from './abstract';
2
2
  import { AbstractRouter } from './abstract';
3
- import type { Navigation, NavigateOptions, HookName, NavigationHook } from '../types';
3
+ import type { Navigation, NavigateOptions, HookName } from '../types';
4
4
  export declare class Router extends AbstractRouter {
5
+ protected defaultRedirectCode: number;
5
6
  protected blocked: boolean;
6
7
  protected redirectCode?: number;
7
- constructor(options: Options & {
8
- onRedirect: (navigation: Navigation) => Promise<void>;
9
- onNotFound: NavigationHook;
10
- onBlock: NavigationHook;
11
- });
8
+ constructor(options: Options);
12
9
  protected onRedirect: (navigation: Navigation) => Promise<void>;
13
10
  dehydrate(): Promise<Navigation>;
14
11
  protected run(navigation: Navigation): Promise<void>;
package/lib/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Url, Query } from '@tinkoff/url';
2
- export declare type Params = Record<string, string | null>;
2
+ export declare type Params = Record<string, string>;
3
3
  export interface Route {
4
4
  name: string;
5
5
  path: string;
@@ -13,8 +13,8 @@ export interface NavigationRoute extends Route {
13
13
  navigateState?: any;
14
14
  }
15
15
  export interface BaseNavigateOptions {
16
- params?: Params;
17
- query?: Query;
16
+ params?: Partial<Params>;
17
+ query?: Partial<Query>;
18
18
  preserveQuery?: boolean;
19
19
  replace?: boolean;
20
20
  hash?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinkoff/router",
3
- "version": "0.1.63",
3
+ "version": "0.1.67",
4
4
  "description": "router",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
@@ -14,7 +14,7 @@
14
14
  ],
15
15
  "repository": {
16
16
  "type": "git",
17
- "url": "git@github.com:TinkoffCreditSystems/tramvai.git"
17
+ "url": "git@github.com:Tinkoff/tramvai.git"
18
18
  },
19
19
  "scripts": {
20
20
  "build": "tramvai-build --for-publish",