import { isInvalidUrl } from '@tinkoff/url' ; import type { Options } from './abstract' ; import { AbstractRouter } from './abstract' ; import { ServerHistory } from '../history/server' ; import type { Navigation , NavigateOptions , HookName } from '../types' ; import { RouteTree } from '../tree/tree' ; import { logger } from '../logger' ; export class Router extends AbstractRouter { protected defaultRedirectCode : number ; protected blocked = false ; protected redirectCode ? : number ; constructor ( options ) { super ( options ) ; this . tree = new RouteTree ( options . routes ) ; this . defaultRedirectCode = options . defaultRedirectCode ?? 308 ; this . history = new ServerHistory ( ) ; } protected onRedirect : ( navigation : Navigation ) => Promise < void > ; async dehydrate ( ) { logger . debug ( { event : 'dehydrate' , navigation : this . lastNavigation , } ) ; return this . lastNavigation ; } protected async run ( navigation ) { if ( this . redirectCode ) { return this . redirect ( navigation , { url : navigation . url . path , code : this . redirectCode } ) ; } if ( this . getCurrentRoute ( ) ) { return this . redirect ( navigation , { url : navigation . url . path , code : navigation . code } ) ; } await super . run ( navigation ) ; } protected async redirect ( navigation , target ) { logger . debug ( { event : 'redirect' , navigation , target , } ) ; this . blocked = true ; return this . onRedirect ( { ... navigation , from : navigation . to , fromUrl : navigation . url , to : null , url : this . resolveUrl ( target ) , code : target . code , } ) ; } protected async notfound ( navigation ) { this . blocked = true ; return super . notfound ( navigation ) ; } protected normalizePathname ( pathname ) { const normalized = super . normalizePathname ( pathname ) ; if ( normalized !== pathname ) { this . redirectCode = this . defaultRedirectCode ; } return normalized ; } protected resolveUrl ( options ) { if ( options . url && isInvalidUrl ( options . url ) ) { this . redirectCode = this . defaultRedirectCode ; } return super . resolveUrl ( options ) ; } protected async runHooks ( hookName , navigation ) { if ( this . blocked ) { return ; } return super . runHooks ( hookName , navigation ) ; } protected async runGuards ( navigation ) { if ( this . blocked ) { return ; } return super . runGuards ( navigation ) ; } }