ui5-lib-guard-router 1.6.0 → 1.6.1

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
@@ -28,7 +28,7 @@ npm install ui5-lib-guard-router
28
28
  ```
29
29
 
30
30
  > [!NOTE]
31
- > The npm package is ~150 KB compressed (~670 KB unpacked) because it ships both pre-built distributables (`dist/`) and TypeScript sources (`src/`) to support multiple [serving options](#serving-the-library). At runtime, the browser loads only the `library-preload.js` bundle (~29 KB).
31
+ > The npm package is ~190 KB compressed (~810 KB unpacked) because it ships both pre-built distributables (`dist/`) and TypeScript sources (`src/`) to support multiple [serving options](#serving-the-library). At runtime, the browser loads only the `library-preload.js` bundle (~29 KB).
32
32
 
33
33
  ### TypeScript
34
34
 
@@ -16,7 +16,7 @@
16
16
  },
17
17
  "buildManifest": {
18
18
  "manifestVersion": "0.2",
19
- "timestamp": "2026-03-30T16:01:41.057Z",
19
+ "timestamp": "2026-04-02T23:45:49.937Z",
20
20
  "versions": {
21
21
  "builderVersion": "4.1.4",
22
22
  "projectVersion": "4.0.13",
@@ -31,7 +31,7 @@
31
31
  "includedTasks": [],
32
32
  "excludedTasks": []
33
33
  },
34
- "version": "1.6.0",
34
+ "version": "1.6.1",
35
35
  "namespace": "ui5/guard/router",
36
36
  "tags": {
37
37
  "/resources/ui5/guard/router/GuardPipeline-dbg.js": {
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  // Generated with TypeScript 6.0.2 / OpenUI5 1.144.0 using:
2
2
  // - typescript@6.0.2
3
- /// <reference path="./resources/ui5/guard/router/GuardPipeline.d.ts"/>
4
- /// <reference path="./resources/ui5/guard/router/types.d.ts"/>
5
3
  /// <reference path="./resources/ui5/guard/router/Router.d.ts"/>
4
+ /// <reference path="./resources/ui5/guard/router/library.d.ts"/>
5
+ /// <reference path="./resources/ui5/guard/router/types.d.ts"/>
6
6
  /// <reference path="./resources/ui5/guard/router/NavigationOutcome.d.ts"/>
7
- /// <reference path="./resources/ui5/guard/router/library.d.ts"/>
7
+ /// <reference path="./resources/ui5/guard/router/GuardPipeline.d.ts"/>
@@ -2,7 +2,7 @@
2
2
  <library xmlns="http://www.sap.com/sap.ui.library.xsd">
3
3
  <name>ui5.guard.router</name>
4
4
  <vendor>Marco</vendor>
5
- <version>1.6.0</version>
5
+ <version>1.6.1</version>
6
6
  <copyright></copyright>
7
7
  <title>UI5 Router extension with async navigation guards</title>
8
8
  <documentation>Extends sap.m.routing.Router with async navigation guards, running before route matching begins.</documentation>
@@ -233,7 +233,7 @@ sap.ui.define(["sap/base/Log"], function (Log) {
233
233
  }
234
234
  if (result !== true) return this._validateLeaveGuardResult(result);
235
235
  } catch (error) {
236
- Log.error(`Leave guard [${i}] on route "${context.fromRoute}" threw, navigation failed`, String(error), LOG_COMPONENT);
236
+ Log.error(`Leave guard [${i}] on route "${context.fromRoute}" threw, navigation failed`, error instanceof Error ? error : String(error), LOG_COMPONENT);
237
237
  if (context.signal.aborted) return false;
238
238
  throw error;
239
239
  }
@@ -278,7 +278,7 @@ sap.ui.define(["sap/base/Log"], function (Log) {
278
278
  }
279
279
  if (result !== true) return this._validateGuardResult(result);
280
280
  } catch (error) {
281
- Log.error(`Enter guard [${i}] on route "${context.toRoute}" threw, navigation failed`, String(error), LOG_COMPONENT);
281
+ Log.error(`Enter guard [${i}] on route "${context.toRoute}" threw, navigation failed`, error instanceof Error ? error : String(error), LOG_COMPONENT);
282
282
  if (context.signal.aborted) return false;
283
283
  throw error;
284
284
  }
@@ -310,7 +310,7 @@ sap.ui.define(["sap/base/Log"], function (Log) {
310
310
  } catch (error) {
311
311
  if (!context.signal.aborted) {
312
312
  const route = isLeaveGuard ? context.fromRoute : context.toRoute;
313
- Log.error(`${label} [${guardIndex}] on route "${route}" threw, navigation failed`, String(error), LOG_COMPONENT);
313
+ Log.error(`${label} [${guardIndex}] on route "${route}" threw, navigation failed`, error instanceof Error ? error : String(error), LOG_COMPONENT);
314
314
  throw error;
315
315
  }
316
316
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"GuardPipeline-dbg.js","names":["LOG_COMPONENT","isGuardRedirect","value","route","length","isPromiseLike","then","GuardPipeline","_globalGuards","_enterGuards","Map","_leaveGuards","addGlobalGuard","guard","push","removeGlobalGuard","index","indexOf","splice","addEnterGuard","_addToGuardMap","removeEnterGuard","_removeFromGuardMap","addLeaveGuard","removeLeaveGuard","clear","evaluate","context","options","hasLeaveGuards","skipLeaveGuards","fromRoute","has","hasEnterGuards","toRoute","action","processEnterResult","enterResult","r","target","catch","error","runEnterPhase","_runEnterGuards","leaveResult","_runLeaveGuards","allowed","signal","aborted","map","key","guards","get","set","delete","registered","slice","i","result","_continueGuardsAsync","candidate","_validateLeaveGuardResult","Log","String","globalResult","_runGuards","_runRouteGuards","_validateGuardResult","pendingResult","currentIndex","onBlock","label","isLeaveGuard","guardIndex","nextResult","warning"],"sources":["GuardPipeline.ts"],"sourcesContent":["import Log from \"sap/base/Log\";\nimport type { GuardFn, GuardContext, GuardResult, GuardRedirect } from \"./types\";\n\nconst LOG_COMPONENT = \"ui5.guard.router.Router\";\n\nfunction isGuardRedirect(value: unknown): value is GuardRedirect {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst { route } = value as GuardRedirect;\n\treturn typeof route === \"string\" && route.length > 0;\n}\n\n/**\n * Promises/A+ thenable detection via duck typing.\n *\n * We intentionally do not use `instanceof Promise` because that misses\n * cross-realm Promises and PromiseLike/thenable objects.\n */\nexport function isPromiseLike<T>(value: unknown): value is PromiseLike<T> {\n\tif ((typeof value !== \"object\" && typeof value !== \"function\") || value === null) {\n\t\treturn false;\n\t}\n\n\treturn typeof (value as PromiseLike<T>).then === \"function\";\n}\n\n/**\n * Normalized result of the guard decision pipeline.\n */\nexport type GuardDecision =\n\t| { action: \"allow\" }\n\t| { action: \"block\" }\n\t| { action: \"redirect\"; target: string | GuardRedirect }\n\t| { action: \"error\"; error: unknown };\n\n/**\n * Standalone guard evaluation pipeline.\n *\n * Owns guard storage (global, enter, leave) and runs the full\n * leave -> global-enter -> route-enter pipeline. Pure logic with\n * no dependency on Router state beyond the current route name\n * passed into evaluate().\n *\n * @namespace ui5.guard.router\n */\nexport default class GuardPipeline {\n\tprivate _globalGuards: GuardFn[] = [];\n\tprivate _enterGuards = new Map<string, GuardFn[]>();\n\tprivate _leaveGuards = new Map<string, GuardFn[]>();\n\n\t/** Register a guard that runs for every navigation. */\n\taddGlobalGuard(guard: GuardFn): void {\n\t\tthis._globalGuards.push(guard);\n\t}\n\n\t/** Remove a previously registered global guard by reference. */\n\tremoveGlobalGuard(guard: GuardFn): void {\n\t\tconst index = this._globalGuards.indexOf(guard);\n\t\tif (index !== -1) {\n\t\t\tthis._globalGuards.splice(index, 1);\n\t\t}\n\t}\n\n\t/**\n\t * Register an enter guard for a specific route.\n\t *\n\t * @param route - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function to register.\n\t */\n\taddEnterGuard(route: string, guard: GuardFn): void {\n\t\tthis._addToGuardMap(this._enterGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove a previously registered enter guard by reference.\n\t *\n\t * @param route - Route name.\n\t * @param guard - Guard function to remove.\n\t */\n\tremoveEnterGuard(route: string, guard: GuardFn): void {\n\t\tthis._removeFromGuardMap(this._enterGuards, route, guard);\n\t}\n\n\t/**\n\t * Register a leave guard for a specific route.\n\t *\n\t * Accepts `GuardFn` to support manifest-declared guards loaded from\n\t * untyped modules. Non-boolean return values are caught at runtime\n\t * by {@link _validateLeaveGuardResult}.\n\t *\n\t * @param route - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function to register as a leave guard.\n\t */\n\taddLeaveGuard(route: string, guard: GuardFn): void {\n\t\tthis._addToGuardMap(this._leaveGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove a previously registered leave guard by reference.\n\t *\n\t * @param route - Route name.\n\t * @param guard - Guard function to remove.\n\t */\n\tremoveLeaveGuard(route: string, guard: GuardFn): void {\n\t\tthis._removeFromGuardMap(this._leaveGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove all registered guards.\n\t */\n\tclear(): void {\n\t\tthis._globalGuards = [];\n\t\tthis._enterGuards.clear();\n\t\tthis._leaveGuards.clear();\n\t}\n\n\t/**\n\t * Run the full guard pipeline (leave -> global enter -> route enter) and\n\t * return a normalized decision. Stays synchronous when all guards return\n\t * plain values; returns a Promise only when an async guard is encountered.\n\t *\n\t * @param context - Complete guard context including AbortSignal.\n\t * `context.fromRoute` controls leave-guard lookup: empty string skips leave guards.\n\t * @param options - Optional evaluation options.\n\t * @param options.skipLeaveGuards - When true, leave guards are skipped even if\n\t * `context.fromRoute` is set. Used by redirect chain hops to avoid re-running\n\t * leave guards while still preserving `fromRoute` in the context.\n\t * @returns A synchronous {@link GuardDecision} when all guards return plain values,\n\t * or a `Promise<GuardDecision>` when at least one guard returns a thenable.\n\t */\n\tevaluate(context: GuardContext, options?: { skipLeaveGuards?: boolean }): GuardDecision | Promise<GuardDecision> {\n\t\tconst hasLeaveGuards =\n\t\t\t!options?.skipLeaveGuards && context.fromRoute !== \"\" && this._leaveGuards.has(context.fromRoute);\n\t\tconst hasEnterGuards =\n\t\t\tthis._globalGuards.length > 0 || (context.toRoute !== \"\" && this._enterGuards.has(context.toRoute));\n\n\t\tif (!hasLeaveGuards && !hasEnterGuards) {\n\t\t\treturn { action: \"allow\" };\n\t\t}\n\n\t\tconst processEnterResult = (\n\t\t\tenterResult: GuardResult | Promise<GuardResult>,\n\t\t): GuardDecision | Promise<GuardDecision> => {\n\t\t\tif (isPromiseLike(enterResult)) {\n\t\t\t\treturn enterResult\n\t\t\t\t\t.then((r: GuardResult): GuardDecision => {\n\t\t\t\t\t\tif (r === true) return { action: \"allow\" };\n\t\t\t\t\t\tif (r === false) return { action: \"block\" };\n\t\t\t\t\t\treturn { action: \"redirect\", target: r };\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error: unknown): GuardDecision => {\n\t\t\t\t\t\treturn { action: \"error\", error };\n\t\t\t\t\t});\n\t\t\t}\n\t\t\tif (enterResult === true) return { action: \"allow\" };\n\t\t\tif (enterResult === false) return { action: \"block\" };\n\t\t\treturn { action: \"redirect\", target: enterResult };\n\t\t};\n\n\t\tconst runEnterPhase = (): GuardDecision | Promise<GuardDecision> => {\n\t\t\tconst enterResult = this._runEnterGuards(context.toRoute, context);\n\t\t\treturn processEnterResult(enterResult);\n\t\t};\n\n\t\ttry {\n\t\t\tif (hasLeaveGuards) {\n\t\t\t\tconst leaveResult = this._runLeaveGuards(context);\n\n\t\t\t\tif (isPromiseLike(leaveResult)) {\n\t\t\t\t\treturn leaveResult\n\t\t\t\t\t\t.then((allowed: boolean): GuardDecision | Promise<GuardDecision> => {\n\t\t\t\t\t\t\tif (allowed !== true) return { action: \"block\" };\n\t\t\t\t\t\t\tif (context.signal.aborted) return { action: \"block\" };\n\t\t\t\t\t\t\treturn runEnterPhase();\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch((error: unknown): GuardDecision => {\n\t\t\t\t\t\t\treturn { action: \"error\", error };\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (leaveResult !== true) return { action: \"block\" };\n\t\t\t}\n\n\t\t\treturn runEnterPhase();\n\t\t} catch (error) {\n\t\t\treturn { action: \"error\", error };\n\t\t}\n\t}\n\n\tprivate _addToGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\t\tlet guards = map.get(key);\n\t\tif (!guards) {\n\t\t\tguards = [];\n\t\t\tmap.set(key, guards);\n\t\t}\n\t\tguards.push(guard);\n\t}\n\n\tprivate _removeFromGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\t\tconst guards = map.get(key);\n\t\tif (!guards) return;\n\t\tconst index = guards.indexOf(guard);\n\t\tif (index !== -1) guards.splice(index, 1);\n\t\tif (guards.length === 0) map.delete(key);\n\t}\n\n\t/**\n\t * Run leave guards for the current route. Returns boolean (no redirects).\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runLeaveGuards(context: GuardContext): boolean | Promise<boolean> {\n\t\tconst registered = this._leaveGuards.get(context.fromRoute);\n\t\tif (!registered || registered.length === 0) return true;\n\n\t\tconst guards = registered.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateLeaveGuardResult(candidate),\n\t\t\t\t\t\t\"Leave guard\",\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t) as Promise<boolean>;\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateLeaveGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Leave guard [${i}] on route \"${context.fromRoute}\" threw, navigation failed`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** Run global guards, then route-specific guards. Stays sync when possible. */\n\tprivate _runEnterGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tconst globalResult = this._runGuards(this._globalGuards, context);\n\n\t\tif (isPromiseLike(globalResult)) {\n\t\t\treturn globalResult.then((result: GuardResult) => {\n\t\t\t\tif (result !== true) return result;\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\treturn this._runRouteGuards(toRoute, context);\n\t\t\t});\n\t\t}\n\t\tif (globalResult !== true) return globalResult;\n\t\treturn this._runRouteGuards(toRoute, context);\n\t}\n\n\t/** Run route-specific guards if any are registered. */\n\tprivate _runRouteGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tif (!toRoute || !this._enterGuards.has(toRoute)) return true;\n\t\treturn this._runGuards(this._enterGuards.get(toRoute)!, context);\n\t}\n\n\t/**\n\t * Run guards sync; switch to async path if a Promise is returned.\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runGuards(guards: GuardFn[], context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tguards = guards.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateGuardResult(candidate),\n\t\t\t\t\t\t\"Enter guard\",\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Enter guard [${i}] on route \"${context.toRoute}\" threw, navigation failed`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Continue guard array async from the first Promise onward.\n\t *\n\t * Shared by both enter and leave guard pipelines. The `onBlock` callback\n\t * determines what to return for non-true results: leave guards always\n\t * return `false`, enter guards validate and may return redirects.\n\t *\n\t * @param isLeaveGuard - When true, error logs reference `fromRoute`; otherwise `toRoute`.\n\t */\n\tprivate async _continueGuardsAsync(\n\t\tpendingResult: PromiseLike<GuardResult>,\n\t\tguards: GuardFn[],\n\t\tcurrentIndex: number,\n\t\tcontext: GuardContext,\n\t\tonBlock: (result: unknown) => GuardResult,\n\t\tlabel: string,\n\t\tisLeaveGuard: boolean,\n\t): Promise<GuardResult> {\n\t\tlet guardIndex = currentIndex;\n\t\ttry {\n\t\t\tconst result = await pendingResult;\n\t\t\tif (result !== true) return onBlock(result);\n\n\t\t\tfor (let i = currentIndex + 1; i < guards.length; i++) {\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tguardIndex = i;\n\t\t\t\tconst nextResult = await guards[i](context);\n\t\t\t\tif (nextResult !== true) return onBlock(nextResult);\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (!context.signal.aborted) {\n\t\t\t\tconst route = isLeaveGuard ? context.fromRoute : context.toRoute;\n\t\t\t\tLog.error(\n\t\t\t\t\t`${label} [${guardIndex}] on route \"${route}\" threw, navigation failed`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/** Validate a non-true guard result; invalid values become false. */\n\tprivate _validateGuardResult(result: unknown): GuardResult {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tif (typeof result === \"string\" && result.length > 0) return result;\n\t\tif (isGuardRedirect(result)) return result;\n\t\tLog.warning(\"Guard returned invalid value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n\n\t/** Validate a leave guard result; non-boolean values log a warning and block. */\n\tprivate _validateLeaveGuardResult(result: unknown): boolean {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tLog.warning(\"Leave guard returned non-boolean value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"GuardPipeline-dbg.js","names":["LOG_COMPONENT","isGuardRedirect","value","route","length","isPromiseLike","then","GuardPipeline","_globalGuards","_enterGuards","Map","_leaveGuards","addGlobalGuard","guard","push","removeGlobalGuard","index","indexOf","splice","addEnterGuard","_addToGuardMap","removeEnterGuard","_removeFromGuardMap","addLeaveGuard","removeLeaveGuard","clear","evaluate","context","options","hasLeaveGuards","skipLeaveGuards","fromRoute","has","hasEnterGuards","toRoute","action","processEnterResult","enterResult","r","target","catch","error","runEnterPhase","_runEnterGuards","leaveResult","_runLeaveGuards","allowed","signal","aborted","map","key","guards","get","set","delete","registered","slice","i","result","_continueGuardsAsync","candidate","_validateLeaveGuardResult","Log","Error","String","globalResult","_runGuards","_runRouteGuards","_validateGuardResult","pendingResult","currentIndex","onBlock","label","isLeaveGuard","guardIndex","nextResult","warning"],"sources":["GuardPipeline.ts"],"sourcesContent":["import Log from \"sap/base/Log\";\nimport type { GuardFn, GuardContext, GuardResult, GuardRedirect } from \"./types\";\n\nconst LOG_COMPONENT = \"ui5.guard.router.Router\";\n\nfunction isGuardRedirect(value: unknown): value is GuardRedirect {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst { route } = value as GuardRedirect;\n\treturn typeof route === \"string\" && route.length > 0;\n}\n\n/**\n * Promises/A+ thenable detection via duck typing.\n *\n * We intentionally do not use `instanceof Promise` because that misses\n * cross-realm Promises and PromiseLike/thenable objects.\n */\nexport function isPromiseLike<T>(value: unknown): value is PromiseLike<T> {\n\tif ((typeof value !== \"object\" && typeof value !== \"function\") || value === null) {\n\t\treturn false;\n\t}\n\n\treturn typeof (value as PromiseLike<T>).then === \"function\";\n}\n\n/**\n * Normalized result of the guard decision pipeline.\n */\nexport type GuardDecision =\n\t| { action: \"allow\" }\n\t| { action: \"block\" }\n\t| { action: \"redirect\"; target: string | GuardRedirect }\n\t| { action: \"error\"; error: unknown };\n\n/**\n * Standalone guard evaluation pipeline.\n *\n * Owns guard storage (global, enter, leave) and runs the full\n * leave -> global-enter -> route-enter pipeline. Pure logic with\n * no dependency on Router state beyond the current route name\n * passed into evaluate().\n *\n * @namespace ui5.guard.router\n */\nexport default class GuardPipeline {\n\tprivate _globalGuards: GuardFn[] = [];\n\tprivate _enterGuards = new Map<string, GuardFn[]>();\n\tprivate _leaveGuards = new Map<string, GuardFn[]>();\n\n\t/** Register a guard that runs for every navigation. */\n\taddGlobalGuard(guard: GuardFn): void {\n\t\tthis._globalGuards.push(guard);\n\t}\n\n\t/** Remove a previously registered global guard by reference. */\n\tremoveGlobalGuard(guard: GuardFn): void {\n\t\tconst index = this._globalGuards.indexOf(guard);\n\t\tif (index !== -1) {\n\t\t\tthis._globalGuards.splice(index, 1);\n\t\t}\n\t}\n\n\t/**\n\t * Register an enter guard for a specific route.\n\t *\n\t * @param route - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function to register.\n\t */\n\taddEnterGuard(route: string, guard: GuardFn): void {\n\t\tthis._addToGuardMap(this._enterGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove a previously registered enter guard by reference.\n\t *\n\t * @param route - Route name.\n\t * @param guard - Guard function to remove.\n\t */\n\tremoveEnterGuard(route: string, guard: GuardFn): void {\n\t\tthis._removeFromGuardMap(this._enterGuards, route, guard);\n\t}\n\n\t/**\n\t * Register a leave guard for a specific route.\n\t *\n\t * Accepts `GuardFn` to support manifest-declared guards loaded from\n\t * untyped modules. Non-boolean return values are caught at runtime\n\t * by {@link _validateLeaveGuardResult}.\n\t *\n\t * @param route - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function to register as a leave guard.\n\t */\n\taddLeaveGuard(route: string, guard: GuardFn): void {\n\t\tthis._addToGuardMap(this._leaveGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove a previously registered leave guard by reference.\n\t *\n\t * @param route - Route name.\n\t * @param guard - Guard function to remove.\n\t */\n\tremoveLeaveGuard(route: string, guard: GuardFn): void {\n\t\tthis._removeFromGuardMap(this._leaveGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove all registered guards.\n\t */\n\tclear(): void {\n\t\tthis._globalGuards = [];\n\t\tthis._enterGuards.clear();\n\t\tthis._leaveGuards.clear();\n\t}\n\n\t/**\n\t * Run the full guard pipeline (leave -> global enter -> route enter) and\n\t * return a normalized decision. Stays synchronous when all guards return\n\t * plain values; returns a Promise only when an async guard is encountered.\n\t *\n\t * @param context - Complete guard context including AbortSignal.\n\t * `context.fromRoute` controls leave-guard lookup: empty string skips leave guards.\n\t * @param options - Optional evaluation options.\n\t * @param options.skipLeaveGuards - When true, leave guards are skipped even if\n\t * `context.fromRoute` is set. Used by redirect chain hops to avoid re-running\n\t * leave guards while still preserving `fromRoute` in the context.\n\t * @returns A synchronous {@link GuardDecision} when all guards return plain values,\n\t * or a `Promise<GuardDecision>` when at least one guard returns a thenable.\n\t */\n\tevaluate(context: GuardContext, options?: { skipLeaveGuards?: boolean }): GuardDecision | Promise<GuardDecision> {\n\t\tconst hasLeaveGuards =\n\t\t\t!options?.skipLeaveGuards && context.fromRoute !== \"\" && this._leaveGuards.has(context.fromRoute);\n\t\tconst hasEnterGuards =\n\t\t\tthis._globalGuards.length > 0 || (context.toRoute !== \"\" && this._enterGuards.has(context.toRoute));\n\n\t\tif (!hasLeaveGuards && !hasEnterGuards) {\n\t\t\treturn { action: \"allow\" };\n\t\t}\n\n\t\tconst processEnterResult = (\n\t\t\tenterResult: GuardResult | Promise<GuardResult>,\n\t\t): GuardDecision | Promise<GuardDecision> => {\n\t\t\tif (isPromiseLike(enterResult)) {\n\t\t\t\treturn enterResult\n\t\t\t\t\t.then((r: GuardResult): GuardDecision => {\n\t\t\t\t\t\tif (r === true) return { action: \"allow\" };\n\t\t\t\t\t\tif (r === false) return { action: \"block\" };\n\t\t\t\t\t\treturn { action: \"redirect\", target: r };\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error: unknown): GuardDecision => {\n\t\t\t\t\t\treturn { action: \"error\", error };\n\t\t\t\t\t});\n\t\t\t}\n\t\t\tif (enterResult === true) return { action: \"allow\" };\n\t\t\tif (enterResult === false) return { action: \"block\" };\n\t\t\treturn { action: \"redirect\", target: enterResult };\n\t\t};\n\n\t\tconst runEnterPhase = (): GuardDecision | Promise<GuardDecision> => {\n\t\t\tconst enterResult = this._runEnterGuards(context.toRoute, context);\n\t\t\treturn processEnterResult(enterResult);\n\t\t};\n\n\t\ttry {\n\t\t\tif (hasLeaveGuards) {\n\t\t\t\tconst leaveResult = this._runLeaveGuards(context);\n\n\t\t\t\tif (isPromiseLike(leaveResult)) {\n\t\t\t\t\treturn leaveResult\n\t\t\t\t\t\t.then((allowed: boolean): GuardDecision | Promise<GuardDecision> => {\n\t\t\t\t\t\t\tif (allowed !== true) return { action: \"block\" };\n\t\t\t\t\t\t\tif (context.signal.aborted) return { action: \"block\" };\n\t\t\t\t\t\t\treturn runEnterPhase();\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch((error: unknown): GuardDecision => {\n\t\t\t\t\t\t\treturn { action: \"error\", error };\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (leaveResult !== true) return { action: \"block\" };\n\t\t\t}\n\n\t\t\treturn runEnterPhase();\n\t\t} catch (error) {\n\t\t\treturn { action: \"error\", error };\n\t\t}\n\t}\n\n\tprivate _addToGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\t\tlet guards = map.get(key);\n\t\tif (!guards) {\n\t\t\tguards = [];\n\t\t\tmap.set(key, guards);\n\t\t}\n\t\tguards.push(guard);\n\t}\n\n\tprivate _removeFromGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\t\tconst guards = map.get(key);\n\t\tif (!guards) return;\n\t\tconst index = guards.indexOf(guard);\n\t\tif (index !== -1) guards.splice(index, 1);\n\t\tif (guards.length === 0) map.delete(key);\n\t}\n\n\t/**\n\t * Run leave guards for the current route. Returns boolean (no redirects).\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runLeaveGuards(context: GuardContext): boolean | Promise<boolean> {\n\t\tconst registered = this._leaveGuards.get(context.fromRoute);\n\t\tif (!registered || registered.length === 0) return true;\n\n\t\tconst guards = registered.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateLeaveGuardResult(candidate),\n\t\t\t\t\t\t\"Leave guard\",\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t) as Promise<boolean>;\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateLeaveGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Leave guard [${i}] on route \"${context.fromRoute}\" threw, navigation failed`,\n\t\t\t\t\terror instanceof Error ? error : String(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** Run global guards, then route-specific guards. Stays sync when possible. */\n\tprivate _runEnterGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tconst globalResult = this._runGuards(this._globalGuards, context);\n\n\t\tif (isPromiseLike(globalResult)) {\n\t\t\treturn globalResult.then((result: GuardResult) => {\n\t\t\t\tif (result !== true) return result;\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\treturn this._runRouteGuards(toRoute, context);\n\t\t\t});\n\t\t}\n\t\tif (globalResult !== true) return globalResult;\n\t\treturn this._runRouteGuards(toRoute, context);\n\t}\n\n\t/** Run route-specific guards if any are registered. */\n\tprivate _runRouteGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tif (!toRoute || !this._enterGuards.has(toRoute)) return true;\n\t\treturn this._runGuards(this._enterGuards.get(toRoute)!, context);\n\t}\n\n\t/**\n\t * Run guards sync; switch to async path if a Promise is returned.\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runGuards(guards: GuardFn[], context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tguards = guards.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateGuardResult(candidate),\n\t\t\t\t\t\t\"Enter guard\",\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Enter guard [${i}] on route \"${context.toRoute}\" threw, navigation failed`,\n\t\t\t\t\terror instanceof Error ? error : String(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Continue guard array async from the first Promise onward.\n\t *\n\t * Shared by both enter and leave guard pipelines. The `onBlock` callback\n\t * determines what to return for non-true results: leave guards always\n\t * return `false`, enter guards validate and may return redirects.\n\t *\n\t * @param isLeaveGuard - When true, error logs reference `fromRoute`; otherwise `toRoute`.\n\t */\n\tprivate async _continueGuardsAsync(\n\t\tpendingResult: PromiseLike<GuardResult>,\n\t\tguards: GuardFn[],\n\t\tcurrentIndex: number,\n\t\tcontext: GuardContext,\n\t\tonBlock: (result: unknown) => GuardResult,\n\t\tlabel: string,\n\t\tisLeaveGuard: boolean,\n\t): Promise<GuardResult> {\n\t\tlet guardIndex = currentIndex;\n\t\ttry {\n\t\t\tconst result = await pendingResult;\n\t\t\tif (result !== true) return onBlock(result);\n\n\t\t\tfor (let i = currentIndex + 1; i < guards.length; i++) {\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tguardIndex = i;\n\t\t\t\tconst nextResult = await guards[i](context);\n\t\t\t\tif (nextResult !== true) return onBlock(nextResult);\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (!context.signal.aborted) {\n\t\t\t\tconst route = isLeaveGuard ? context.fromRoute : context.toRoute;\n\t\t\t\tLog.error(\n\t\t\t\t\t`${label} [${guardIndex}] on route \"${route}\" threw, navigation failed`,\n\t\t\t\t\terror instanceof Error ? error : String(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/** Validate a non-true guard result; invalid values become false. */\n\tprivate _validateGuardResult(result: unknown): GuardResult {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tif (typeof result === \"string\" && result.length > 0) return result;\n\t\tif (isGuardRedirect(result)) return result;\n\t\tLog.warning(\"Guard returned invalid value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n\n\t/** Validate a leave guard result; non-boolean values log a warning and block. */\n\tprivate _validateLeaveGuardResult(result: unknown): boolean {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tLog.warning(\"Leave guard returned non-boolean value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,2 +1,2 @@
1
- sap.ui.define(["sap/base/Log"],function(r){"use strict";const e="ui5.guard.router.Router";function t(r){if(typeof r!=="object"||r===null){return false}const{route:e}=r;return typeof e==="string"&&e.length>0}function a(r){if(typeof r!=="object"&&typeof r!=="function"||r===null){return false}return typeof r.then==="function"}class n{_globalGuards=[];_enterGuards=new Map;_leaveGuards=new Map;addGlobalGuard(r){this._globalGuards.push(r)}removeGlobalGuard(r){const e=this._globalGuards.indexOf(r);if(e!==-1){this._globalGuards.splice(e,1)}}addEnterGuard(r,e){this._addToGuardMap(this._enterGuards,r,e)}removeEnterGuard(r,e){this._removeFromGuardMap(this._enterGuards,r,e)}addLeaveGuard(r,e){this._addToGuardMap(this._leaveGuards,r,e)}removeLeaveGuard(r,e){this._removeFromGuardMap(this._leaveGuards,r,e)}clear(){this._globalGuards=[];this._enterGuards.clear();this._leaveGuards.clear()}evaluate(r,e){const t=!e?.skipLeaveGuards&&r.fromRoute!==""&&this._leaveGuards.has(r.fromRoute);const n=this._globalGuards.length>0||r.toRoute!==""&&this._enterGuards.has(r.toRoute);if(!t&&!n){return{action:"allow"}}const u=r=>{if(a(r)){return r.then(r=>{if(r===true)return{action:"allow"};if(r===false)return{action:"block"};return{action:"redirect",target:r}}).catch(r=>({action:"error",error:r}))}if(r===true)return{action:"allow"};if(r===false)return{action:"block"};return{action:"redirect",target:r}};const o=()=>{const e=this._runEnterGuards(r.toRoute,r);return u(e)};try{if(t){const e=this._runLeaveGuards(r);if(a(e)){return e.then(e=>{if(e!==true)return{action:"block"};if(r.signal.aborted)return{action:"block"};return o()}).catch(r=>({action:"error",error:r}))}if(e!==true)return{action:"block"}}return o()}catch(r){return{action:"error",error:r}}}_addToGuardMap(r,e,t){let a=r.get(e);if(!a){a=[];r.set(e,a)}a.push(t)}_removeFromGuardMap(r,e,t){const a=r.get(e);if(!a)return;const n=a.indexOf(t);if(n!==-1)a.splice(n,1);if(a.length===0)r.delete(e)}_runLeaveGuards(t){const n=this._leaveGuards.get(t.fromRoute);if(!n||n.length===0)return true;const u=n.slice();for(let n=0;n<u.length;n++){try{const r=u[n](t);if(a(r)){return this._continueGuardsAsync(r,u,n,t,r=>this._validateLeaveGuardResult(r),"Leave guard",true)}if(r!==true)return this._validateLeaveGuardResult(r)}catch(a){r.error(`Leave guard [${n}] on route "${t.fromRoute}" threw, navigation failed`,String(a),e);if(t.signal.aborted)return false;throw a}}return true}_runEnterGuards(r,e){const t=this._runGuards(this._globalGuards,e);if(a(t)){return t.then(t=>{if(t!==true)return t;if(e.signal.aborted)return false;return this._runRouteGuards(r,e)})}if(t!==true)return t;return this._runRouteGuards(r,e)}_runRouteGuards(r,e){if(!r||!this._enterGuards.has(r))return true;return this._runGuards(this._enterGuards.get(r),e)}_runGuards(t,n){t=t.slice();for(let u=0;u<t.length;u++){try{const r=t[u](n);if(a(r)){return this._continueGuardsAsync(r,t,u,n,r=>this._validateGuardResult(r),"Enter guard",false)}if(r!==true)return this._validateGuardResult(r)}catch(t){r.error(`Enter guard [${u}] on route "${n.toRoute}" threw, navigation failed`,String(t),e);if(n.signal.aborted)return false;throw t}}return true}async _continueGuardsAsync(t,a,n,u,o,i,s){let l=n;try{const r=await t;if(r!==true)return o(r);for(let r=n+1;r<a.length;r++){if(u.signal.aborted)return false;l=r;const e=await a[r](u);if(e!==true)return o(e)}return true}catch(t){if(!u.signal.aborted){const a=s?u.fromRoute:u.toRoute;r.error(`${i} [${l}] on route "${a}" threw, navigation failed`,String(t),e);throw t}return false}}_validateGuardResult(a){if(typeof a==="boolean")return a;if(typeof a==="string"&&a.length>0)return a;if(t(a))return a;r.warning("Guard returned invalid value, treating as block",String(a),e);return false}_validateLeaveGuardResult(t){if(typeof t==="boolean")return t;r.warning("Leave guard returned non-boolean value, treating as block",String(t),e);return false}}n.isPromiseLike=a;return n});
1
+ sap.ui.define(["sap/base/Log"],function(r){"use strict";const e="ui5.guard.router.Router";function t(r){if(typeof r!=="object"||r===null){return false}const{route:e}=r;return typeof e==="string"&&e.length>0}function a(r){if(typeof r!=="object"&&typeof r!=="function"||r===null){return false}return typeof r.then==="function"}class n{_globalGuards=[];_enterGuards=new Map;_leaveGuards=new Map;addGlobalGuard(r){this._globalGuards.push(r)}removeGlobalGuard(r){const e=this._globalGuards.indexOf(r);if(e!==-1){this._globalGuards.splice(e,1)}}addEnterGuard(r,e){this._addToGuardMap(this._enterGuards,r,e)}removeEnterGuard(r,e){this._removeFromGuardMap(this._enterGuards,r,e)}addLeaveGuard(r,e){this._addToGuardMap(this._leaveGuards,r,e)}removeLeaveGuard(r,e){this._removeFromGuardMap(this._leaveGuards,r,e)}clear(){this._globalGuards=[];this._enterGuards.clear();this._leaveGuards.clear()}evaluate(r,e){const t=!e?.skipLeaveGuards&&r.fromRoute!==""&&this._leaveGuards.has(r.fromRoute);const n=this._globalGuards.length>0||r.toRoute!==""&&this._enterGuards.has(r.toRoute);if(!t&&!n){return{action:"allow"}}const u=r=>{if(a(r)){return r.then(r=>{if(r===true)return{action:"allow"};if(r===false)return{action:"block"};return{action:"redirect",target:r}}).catch(r=>({action:"error",error:r}))}if(r===true)return{action:"allow"};if(r===false)return{action:"block"};return{action:"redirect",target:r}};const o=()=>{const e=this._runEnterGuards(r.toRoute,r);return u(e)};try{if(t){const e=this._runLeaveGuards(r);if(a(e)){return e.then(e=>{if(e!==true)return{action:"block"};if(r.signal.aborted)return{action:"block"};return o()}).catch(r=>({action:"error",error:r}))}if(e!==true)return{action:"block"}}return o()}catch(r){return{action:"error",error:r}}}_addToGuardMap(r,e,t){let a=r.get(e);if(!a){a=[];r.set(e,a)}a.push(t)}_removeFromGuardMap(r,e,t){const a=r.get(e);if(!a)return;const n=a.indexOf(t);if(n!==-1)a.splice(n,1);if(a.length===0)r.delete(e)}_runLeaveGuards(t){const n=this._leaveGuards.get(t.fromRoute);if(!n||n.length===0)return true;const u=n.slice();for(let n=0;n<u.length;n++){try{const r=u[n](t);if(a(r)){return this._continueGuardsAsync(r,u,n,t,r=>this._validateLeaveGuardResult(r),"Leave guard",true)}if(r!==true)return this._validateLeaveGuardResult(r)}catch(a){r.error(`Leave guard [${n}] on route "${t.fromRoute}" threw, navigation failed`,a instanceof Error?a:String(a),e);if(t.signal.aborted)return false;throw a}}return true}_runEnterGuards(r,e){const t=this._runGuards(this._globalGuards,e);if(a(t)){return t.then(t=>{if(t!==true)return t;if(e.signal.aborted)return false;return this._runRouteGuards(r,e)})}if(t!==true)return t;return this._runRouteGuards(r,e)}_runRouteGuards(r,e){if(!r||!this._enterGuards.has(r))return true;return this._runGuards(this._enterGuards.get(r),e)}_runGuards(t,n){t=t.slice();for(let u=0;u<t.length;u++){try{const r=t[u](n);if(a(r)){return this._continueGuardsAsync(r,t,u,n,r=>this._validateGuardResult(r),"Enter guard",false)}if(r!==true)return this._validateGuardResult(r)}catch(t){r.error(`Enter guard [${u}] on route "${n.toRoute}" threw, navigation failed`,t instanceof Error?t:String(t),e);if(n.signal.aborted)return false;throw t}}return true}async _continueGuardsAsync(t,a,n,u,o,i,s){let l=n;try{const r=await t;if(r!==true)return o(r);for(let r=n+1;r<a.length;r++){if(u.signal.aborted)return false;l=r;const e=await a[r](u);if(e!==true)return o(e)}return true}catch(t){if(!u.signal.aborted){const a=s?u.fromRoute:u.toRoute;r.error(`${i} [${l}] on route "${a}" threw, navigation failed`,t instanceof Error?t:String(t),e);throw t}return false}}_validateGuardResult(a){if(typeof a==="boolean")return a;if(typeof a==="string"&&a.length>0)return a;if(t(a))return a;r.warning("Guard returned invalid value, treating as block",String(a),e);return false}_validateLeaveGuardResult(t){if(typeof t==="boolean")return t;r.warning("Leave guard returned non-boolean value, treating as block",String(t),e);return false}}n.isPromiseLike=a;return n});
2
2
  //# sourceMappingURL=GuardPipeline.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"GuardPipeline.js","names":["LOG_COMPONENT","isGuardRedirect","value","route","length","isPromiseLike","then","GuardPipeline","_globalGuards","_enterGuards","Map","_leaveGuards","addGlobalGuard","guard","this","push","removeGlobalGuard","index","indexOf","splice","addEnterGuard","_addToGuardMap","removeEnterGuard","_removeFromGuardMap","addLeaveGuard","removeLeaveGuard","clear","evaluate","context","options","hasLeaveGuards","skipLeaveGuards","fromRoute","has","hasEnterGuards","toRoute","action","processEnterResult","enterResult","r","target","catch","error","runEnterPhase","_runEnterGuards","leaveResult","_runLeaveGuards","allowed","signal","aborted","map","key","guards","get","set","delete","registered","slice","i","result","_continueGuardsAsync","candidate","_validateLeaveGuardResult","Log","String","globalResult","_runGuards","_runRouteGuards","_validateGuardResult","pendingResult","currentIndex","onBlock","label","isLeaveGuard","guardIndex","nextResult","warning"],"sources":["GuardPipeline.ts"],"sourcesContent":["import Log from \"sap/base/Log\";\nimport type { GuardFn, GuardContext, GuardResult, GuardRedirect } from \"./types\";\n\nconst LOG_COMPONENT = \"ui5.guard.router.Router\";\n\nfunction isGuardRedirect(value: unknown): value is GuardRedirect {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst { route } = value as GuardRedirect;\n\treturn typeof route === \"string\" && route.length > 0;\n}\n\n/**\n * Promises/A+ thenable detection via duck typing.\n *\n * We intentionally do not use `instanceof Promise` because that misses\n * cross-realm Promises and PromiseLike/thenable objects.\n */\nexport function isPromiseLike<T>(value: unknown): value is PromiseLike<T> {\n\tif ((typeof value !== \"object\" && typeof value !== \"function\") || value === null) {\n\t\treturn false;\n\t}\n\n\treturn typeof (value as PromiseLike<T>).then === \"function\";\n}\n\n/**\n * Normalized result of the guard decision pipeline.\n */\nexport type GuardDecision =\n\t| { action: \"allow\" }\n\t| { action: \"block\" }\n\t| { action: \"redirect\"; target: string | GuardRedirect }\n\t| { action: \"error\"; error: unknown };\n\n/**\n * Standalone guard evaluation pipeline.\n *\n * Owns guard storage (global, enter, leave) and runs the full\n * leave -> global-enter -> route-enter pipeline. Pure logic with\n * no dependency on Router state beyond the current route name\n * passed into evaluate().\n *\n * @namespace ui5.guard.router\n */\nexport default class GuardPipeline {\n\tprivate _globalGuards: GuardFn[] = [];\n\tprivate _enterGuards = new Map<string, GuardFn[]>();\n\tprivate _leaveGuards = new Map<string, GuardFn[]>();\n\n\t/** Register a guard that runs for every navigation. */\n\taddGlobalGuard(guard: GuardFn): void {\n\t\tthis._globalGuards.push(guard);\n\t}\n\n\t/** Remove a previously registered global guard by reference. */\n\tremoveGlobalGuard(guard: GuardFn): void {\n\t\tconst index = this._globalGuards.indexOf(guard);\n\t\tif (index !== -1) {\n\t\t\tthis._globalGuards.splice(index, 1);\n\t\t}\n\t}\n\n\t/**\n\t * Register an enter guard for a specific route.\n\t *\n\t * @param route - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function to register.\n\t */\n\taddEnterGuard(route: string, guard: GuardFn): void {\n\t\tthis._addToGuardMap(this._enterGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove a previously registered enter guard by reference.\n\t *\n\t * @param route - Route name.\n\t * @param guard - Guard function to remove.\n\t */\n\tremoveEnterGuard(route: string, guard: GuardFn): void {\n\t\tthis._removeFromGuardMap(this._enterGuards, route, guard);\n\t}\n\n\t/**\n\t * Register a leave guard for a specific route.\n\t *\n\t * Accepts `GuardFn` to support manifest-declared guards loaded from\n\t * untyped modules. Non-boolean return values are caught at runtime\n\t * by {@link _validateLeaveGuardResult}.\n\t *\n\t * @param route - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function to register as a leave guard.\n\t */\n\taddLeaveGuard(route: string, guard: GuardFn): void {\n\t\tthis._addToGuardMap(this._leaveGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove a previously registered leave guard by reference.\n\t *\n\t * @param route - Route name.\n\t * @param guard - Guard function to remove.\n\t */\n\tremoveLeaveGuard(route: string, guard: GuardFn): void {\n\t\tthis._removeFromGuardMap(this._leaveGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove all registered guards.\n\t */\n\tclear(): void {\n\t\tthis._globalGuards = [];\n\t\tthis._enterGuards.clear();\n\t\tthis._leaveGuards.clear();\n\t}\n\n\t/**\n\t * Run the full guard pipeline (leave -> global enter -> route enter) and\n\t * return a normalized decision. Stays synchronous when all guards return\n\t * plain values; returns a Promise only when an async guard is encountered.\n\t *\n\t * @param context - Complete guard context including AbortSignal.\n\t * `context.fromRoute` controls leave-guard lookup: empty string skips leave guards.\n\t * @param options - Optional evaluation options.\n\t * @param options.skipLeaveGuards - When true, leave guards are skipped even if\n\t * `context.fromRoute` is set. Used by redirect chain hops to avoid re-running\n\t * leave guards while still preserving `fromRoute` in the context.\n\t * @returns A synchronous {@link GuardDecision} when all guards return plain values,\n\t * or a `Promise<GuardDecision>` when at least one guard returns a thenable.\n\t */\n\tevaluate(context: GuardContext, options?: { skipLeaveGuards?: boolean }): GuardDecision | Promise<GuardDecision> {\n\t\tconst hasLeaveGuards =\n\t\t\t!options?.skipLeaveGuards && context.fromRoute !== \"\" && this._leaveGuards.has(context.fromRoute);\n\t\tconst hasEnterGuards =\n\t\t\tthis._globalGuards.length > 0 || (context.toRoute !== \"\" && this._enterGuards.has(context.toRoute));\n\n\t\tif (!hasLeaveGuards && !hasEnterGuards) {\n\t\t\treturn { action: \"allow\" };\n\t\t}\n\n\t\tconst processEnterResult = (\n\t\t\tenterResult: GuardResult | Promise<GuardResult>,\n\t\t): GuardDecision | Promise<GuardDecision> => {\n\t\t\tif (isPromiseLike(enterResult)) {\n\t\t\t\treturn enterResult\n\t\t\t\t\t.then((r: GuardResult): GuardDecision => {\n\t\t\t\t\t\tif (r === true) return { action: \"allow\" };\n\t\t\t\t\t\tif (r === false) return { action: \"block\" };\n\t\t\t\t\t\treturn { action: \"redirect\", target: r };\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error: unknown): GuardDecision => {\n\t\t\t\t\t\treturn { action: \"error\", error };\n\t\t\t\t\t});\n\t\t\t}\n\t\t\tif (enterResult === true) return { action: \"allow\" };\n\t\t\tif (enterResult === false) return { action: \"block\" };\n\t\t\treturn { action: \"redirect\", target: enterResult };\n\t\t};\n\n\t\tconst runEnterPhase = (): GuardDecision | Promise<GuardDecision> => {\n\t\t\tconst enterResult = this._runEnterGuards(context.toRoute, context);\n\t\t\treturn processEnterResult(enterResult);\n\t\t};\n\n\t\ttry {\n\t\t\tif (hasLeaveGuards) {\n\t\t\t\tconst leaveResult = this._runLeaveGuards(context);\n\n\t\t\t\tif (isPromiseLike(leaveResult)) {\n\t\t\t\t\treturn leaveResult\n\t\t\t\t\t\t.then((allowed: boolean): GuardDecision | Promise<GuardDecision> => {\n\t\t\t\t\t\t\tif (allowed !== true) return { action: \"block\" };\n\t\t\t\t\t\t\tif (context.signal.aborted) return { action: \"block\" };\n\t\t\t\t\t\t\treturn runEnterPhase();\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch((error: unknown): GuardDecision => {\n\t\t\t\t\t\t\treturn { action: \"error\", error };\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (leaveResult !== true) return { action: \"block\" };\n\t\t\t}\n\n\t\t\treturn runEnterPhase();\n\t\t} catch (error) {\n\t\t\treturn { action: \"error\", error };\n\t\t}\n\t}\n\n\tprivate _addToGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\t\tlet guards = map.get(key);\n\t\tif (!guards) {\n\t\t\tguards = [];\n\t\t\tmap.set(key, guards);\n\t\t}\n\t\tguards.push(guard);\n\t}\n\n\tprivate _removeFromGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\t\tconst guards = map.get(key);\n\t\tif (!guards) return;\n\t\tconst index = guards.indexOf(guard);\n\t\tif (index !== -1) guards.splice(index, 1);\n\t\tif (guards.length === 0) map.delete(key);\n\t}\n\n\t/**\n\t * Run leave guards for the current route. Returns boolean (no redirects).\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runLeaveGuards(context: GuardContext): boolean | Promise<boolean> {\n\t\tconst registered = this._leaveGuards.get(context.fromRoute);\n\t\tif (!registered || registered.length === 0) return true;\n\n\t\tconst guards = registered.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateLeaveGuardResult(candidate),\n\t\t\t\t\t\t\"Leave guard\",\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t) as Promise<boolean>;\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateLeaveGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Leave guard [${i}] on route \"${context.fromRoute}\" threw, navigation failed`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** Run global guards, then route-specific guards. Stays sync when possible. */\n\tprivate _runEnterGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tconst globalResult = this._runGuards(this._globalGuards, context);\n\n\t\tif (isPromiseLike(globalResult)) {\n\t\t\treturn globalResult.then((result: GuardResult) => {\n\t\t\t\tif (result !== true) return result;\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\treturn this._runRouteGuards(toRoute, context);\n\t\t\t});\n\t\t}\n\t\tif (globalResult !== true) return globalResult;\n\t\treturn this._runRouteGuards(toRoute, context);\n\t}\n\n\t/** Run route-specific guards if any are registered. */\n\tprivate _runRouteGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tif (!toRoute || !this._enterGuards.has(toRoute)) return true;\n\t\treturn this._runGuards(this._enterGuards.get(toRoute)!, context);\n\t}\n\n\t/**\n\t * Run guards sync; switch to async path if a Promise is returned.\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runGuards(guards: GuardFn[], context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tguards = guards.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateGuardResult(candidate),\n\t\t\t\t\t\t\"Enter guard\",\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Enter guard [${i}] on route \"${context.toRoute}\" threw, navigation failed`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Continue guard array async from the first Promise onward.\n\t *\n\t * Shared by both enter and leave guard pipelines. The `onBlock` callback\n\t * determines what to return for non-true results: leave guards always\n\t * return `false`, enter guards validate and may return redirects.\n\t *\n\t * @param isLeaveGuard - When true, error logs reference `fromRoute`; otherwise `toRoute`.\n\t */\n\tprivate async _continueGuardsAsync(\n\t\tpendingResult: PromiseLike<GuardResult>,\n\t\tguards: GuardFn[],\n\t\tcurrentIndex: number,\n\t\tcontext: GuardContext,\n\t\tonBlock: (result: unknown) => GuardResult,\n\t\tlabel: string,\n\t\tisLeaveGuard: boolean,\n\t): Promise<GuardResult> {\n\t\tlet guardIndex = currentIndex;\n\t\ttry {\n\t\t\tconst result = await pendingResult;\n\t\t\tif (result !== true) return onBlock(result);\n\n\t\t\tfor (let i = currentIndex + 1; i < guards.length; i++) {\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tguardIndex = i;\n\t\t\t\tconst nextResult = await guards[i](context);\n\t\t\t\tif (nextResult !== true) return onBlock(nextResult);\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (!context.signal.aborted) {\n\t\t\t\tconst route = isLeaveGuard ? context.fromRoute : context.toRoute;\n\t\t\t\tLog.error(\n\t\t\t\t\t`${label} [${guardIndex}] on route \"${route}\" threw, navigation failed`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/** Validate a non-true guard result; invalid values become false. */\n\tprivate _validateGuardResult(result: unknown): GuardResult {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tif (typeof result === \"string\" && result.length > 0) return result;\n\t\tif (isGuardRedirect(result)) return result;\n\t\tLog.warning(\"Guard returned invalid value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n\n\t/** Validate a leave guard result; non-boolean values log a warning and block. */\n\tprivate _validateLeaveGuardResult(result: unknown): boolean {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tLog.warning(\"Leave guard returned non-boolean value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"GuardPipeline.js","names":["LOG_COMPONENT","isGuardRedirect","value","route","length","isPromiseLike","then","GuardPipeline","_globalGuards","_enterGuards","Map","_leaveGuards","addGlobalGuard","guard","this","push","removeGlobalGuard","index","indexOf","splice","addEnterGuard","_addToGuardMap","removeEnterGuard","_removeFromGuardMap","addLeaveGuard","removeLeaveGuard","clear","evaluate","context","options","hasLeaveGuards","skipLeaveGuards","fromRoute","has","hasEnterGuards","toRoute","action","processEnterResult","enterResult","r","target","catch","error","runEnterPhase","_runEnterGuards","leaveResult","_runLeaveGuards","allowed","signal","aborted","map","key","guards","get","set","delete","registered","slice","i","result","_continueGuardsAsync","candidate","_validateLeaveGuardResult","Log","Error","String","globalResult","_runGuards","_runRouteGuards","_validateGuardResult","pendingResult","currentIndex","onBlock","label","isLeaveGuard","guardIndex","nextResult","warning"],"sources":["GuardPipeline.ts"],"sourcesContent":["import Log from \"sap/base/Log\";\nimport type { GuardFn, GuardContext, GuardResult, GuardRedirect } from \"./types\";\n\nconst LOG_COMPONENT = \"ui5.guard.router.Router\";\n\nfunction isGuardRedirect(value: unknown): value is GuardRedirect {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst { route } = value as GuardRedirect;\n\treturn typeof route === \"string\" && route.length > 0;\n}\n\n/**\n * Promises/A+ thenable detection via duck typing.\n *\n * We intentionally do not use `instanceof Promise` because that misses\n * cross-realm Promises and PromiseLike/thenable objects.\n */\nexport function isPromiseLike<T>(value: unknown): value is PromiseLike<T> {\n\tif ((typeof value !== \"object\" && typeof value !== \"function\") || value === null) {\n\t\treturn false;\n\t}\n\n\treturn typeof (value as PromiseLike<T>).then === \"function\";\n}\n\n/**\n * Normalized result of the guard decision pipeline.\n */\nexport type GuardDecision =\n\t| { action: \"allow\" }\n\t| { action: \"block\" }\n\t| { action: \"redirect\"; target: string | GuardRedirect }\n\t| { action: \"error\"; error: unknown };\n\n/**\n * Standalone guard evaluation pipeline.\n *\n * Owns guard storage (global, enter, leave) and runs the full\n * leave -> global-enter -> route-enter pipeline. Pure logic with\n * no dependency on Router state beyond the current route name\n * passed into evaluate().\n *\n * @namespace ui5.guard.router\n */\nexport default class GuardPipeline {\n\tprivate _globalGuards: GuardFn[] = [];\n\tprivate _enterGuards = new Map<string, GuardFn[]>();\n\tprivate _leaveGuards = new Map<string, GuardFn[]>();\n\n\t/** Register a guard that runs for every navigation. */\n\taddGlobalGuard(guard: GuardFn): void {\n\t\tthis._globalGuards.push(guard);\n\t}\n\n\t/** Remove a previously registered global guard by reference. */\n\tremoveGlobalGuard(guard: GuardFn): void {\n\t\tconst index = this._globalGuards.indexOf(guard);\n\t\tif (index !== -1) {\n\t\t\tthis._globalGuards.splice(index, 1);\n\t\t}\n\t}\n\n\t/**\n\t * Register an enter guard for a specific route.\n\t *\n\t * @param route - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function to register.\n\t */\n\taddEnterGuard(route: string, guard: GuardFn): void {\n\t\tthis._addToGuardMap(this._enterGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove a previously registered enter guard by reference.\n\t *\n\t * @param route - Route name.\n\t * @param guard - Guard function to remove.\n\t */\n\tremoveEnterGuard(route: string, guard: GuardFn): void {\n\t\tthis._removeFromGuardMap(this._enterGuards, route, guard);\n\t}\n\n\t/**\n\t * Register a leave guard for a specific route.\n\t *\n\t * Accepts `GuardFn` to support manifest-declared guards loaded from\n\t * untyped modules. Non-boolean return values are caught at runtime\n\t * by {@link _validateLeaveGuardResult}.\n\t *\n\t * @param route - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function to register as a leave guard.\n\t */\n\taddLeaveGuard(route: string, guard: GuardFn): void {\n\t\tthis._addToGuardMap(this._leaveGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove a previously registered leave guard by reference.\n\t *\n\t * @param route - Route name.\n\t * @param guard - Guard function to remove.\n\t */\n\tremoveLeaveGuard(route: string, guard: GuardFn): void {\n\t\tthis._removeFromGuardMap(this._leaveGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove all registered guards.\n\t */\n\tclear(): void {\n\t\tthis._globalGuards = [];\n\t\tthis._enterGuards.clear();\n\t\tthis._leaveGuards.clear();\n\t}\n\n\t/**\n\t * Run the full guard pipeline (leave -> global enter -> route enter) and\n\t * return a normalized decision. Stays synchronous when all guards return\n\t * plain values; returns a Promise only when an async guard is encountered.\n\t *\n\t * @param context - Complete guard context including AbortSignal.\n\t * `context.fromRoute` controls leave-guard lookup: empty string skips leave guards.\n\t * @param options - Optional evaluation options.\n\t * @param options.skipLeaveGuards - When true, leave guards are skipped even if\n\t * `context.fromRoute` is set. Used by redirect chain hops to avoid re-running\n\t * leave guards while still preserving `fromRoute` in the context.\n\t * @returns A synchronous {@link GuardDecision} when all guards return plain values,\n\t * or a `Promise<GuardDecision>` when at least one guard returns a thenable.\n\t */\n\tevaluate(context: GuardContext, options?: { skipLeaveGuards?: boolean }): GuardDecision | Promise<GuardDecision> {\n\t\tconst hasLeaveGuards =\n\t\t\t!options?.skipLeaveGuards && context.fromRoute !== \"\" && this._leaveGuards.has(context.fromRoute);\n\t\tconst hasEnterGuards =\n\t\t\tthis._globalGuards.length > 0 || (context.toRoute !== \"\" && this._enterGuards.has(context.toRoute));\n\n\t\tif (!hasLeaveGuards && !hasEnterGuards) {\n\t\t\treturn { action: \"allow\" };\n\t\t}\n\n\t\tconst processEnterResult = (\n\t\t\tenterResult: GuardResult | Promise<GuardResult>,\n\t\t): GuardDecision | Promise<GuardDecision> => {\n\t\t\tif (isPromiseLike(enterResult)) {\n\t\t\t\treturn enterResult\n\t\t\t\t\t.then((r: GuardResult): GuardDecision => {\n\t\t\t\t\t\tif (r === true) return { action: \"allow\" };\n\t\t\t\t\t\tif (r === false) return { action: \"block\" };\n\t\t\t\t\t\treturn { action: \"redirect\", target: r };\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error: unknown): GuardDecision => {\n\t\t\t\t\t\treturn { action: \"error\", error };\n\t\t\t\t\t});\n\t\t\t}\n\t\t\tif (enterResult === true) return { action: \"allow\" };\n\t\t\tif (enterResult === false) return { action: \"block\" };\n\t\t\treturn { action: \"redirect\", target: enterResult };\n\t\t};\n\n\t\tconst runEnterPhase = (): GuardDecision | Promise<GuardDecision> => {\n\t\t\tconst enterResult = this._runEnterGuards(context.toRoute, context);\n\t\t\treturn processEnterResult(enterResult);\n\t\t};\n\n\t\ttry {\n\t\t\tif (hasLeaveGuards) {\n\t\t\t\tconst leaveResult = this._runLeaveGuards(context);\n\n\t\t\t\tif (isPromiseLike(leaveResult)) {\n\t\t\t\t\treturn leaveResult\n\t\t\t\t\t\t.then((allowed: boolean): GuardDecision | Promise<GuardDecision> => {\n\t\t\t\t\t\t\tif (allowed !== true) return { action: \"block\" };\n\t\t\t\t\t\t\tif (context.signal.aborted) return { action: \"block\" };\n\t\t\t\t\t\t\treturn runEnterPhase();\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch((error: unknown): GuardDecision => {\n\t\t\t\t\t\t\treturn { action: \"error\", error };\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (leaveResult !== true) return { action: \"block\" };\n\t\t\t}\n\n\t\t\treturn runEnterPhase();\n\t\t} catch (error) {\n\t\t\treturn { action: \"error\", error };\n\t\t}\n\t}\n\n\tprivate _addToGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\t\tlet guards = map.get(key);\n\t\tif (!guards) {\n\t\t\tguards = [];\n\t\t\tmap.set(key, guards);\n\t\t}\n\t\tguards.push(guard);\n\t}\n\n\tprivate _removeFromGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\t\tconst guards = map.get(key);\n\t\tif (!guards) return;\n\t\tconst index = guards.indexOf(guard);\n\t\tif (index !== -1) guards.splice(index, 1);\n\t\tif (guards.length === 0) map.delete(key);\n\t}\n\n\t/**\n\t * Run leave guards for the current route. Returns boolean (no redirects).\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runLeaveGuards(context: GuardContext): boolean | Promise<boolean> {\n\t\tconst registered = this._leaveGuards.get(context.fromRoute);\n\t\tif (!registered || registered.length === 0) return true;\n\n\t\tconst guards = registered.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateLeaveGuardResult(candidate),\n\t\t\t\t\t\t\"Leave guard\",\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t) as Promise<boolean>;\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateLeaveGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Leave guard [${i}] on route \"${context.fromRoute}\" threw, navigation failed`,\n\t\t\t\t\terror instanceof Error ? error : String(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** Run global guards, then route-specific guards. Stays sync when possible. */\n\tprivate _runEnterGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tconst globalResult = this._runGuards(this._globalGuards, context);\n\n\t\tif (isPromiseLike(globalResult)) {\n\t\t\treturn globalResult.then((result: GuardResult) => {\n\t\t\t\tif (result !== true) return result;\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\treturn this._runRouteGuards(toRoute, context);\n\t\t\t});\n\t\t}\n\t\tif (globalResult !== true) return globalResult;\n\t\treturn this._runRouteGuards(toRoute, context);\n\t}\n\n\t/** Run route-specific guards if any are registered. */\n\tprivate _runRouteGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tif (!toRoute || !this._enterGuards.has(toRoute)) return true;\n\t\treturn this._runGuards(this._enterGuards.get(toRoute)!, context);\n\t}\n\n\t/**\n\t * Run guards sync; switch to async path if a Promise is returned.\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runGuards(guards: GuardFn[], context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tguards = guards.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateGuardResult(candidate),\n\t\t\t\t\t\t\"Enter guard\",\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Enter guard [${i}] on route \"${context.toRoute}\" threw, navigation failed`,\n\t\t\t\t\terror instanceof Error ? error : String(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Continue guard array async from the first Promise onward.\n\t *\n\t * Shared by both enter and leave guard pipelines. The `onBlock` callback\n\t * determines what to return for non-true results: leave guards always\n\t * return `false`, enter guards validate and may return redirects.\n\t *\n\t * @param isLeaveGuard - When true, error logs reference `fromRoute`; otherwise `toRoute`.\n\t */\n\tprivate async _continueGuardsAsync(\n\t\tpendingResult: PromiseLike<GuardResult>,\n\t\tguards: GuardFn[],\n\t\tcurrentIndex: number,\n\t\tcontext: GuardContext,\n\t\tonBlock: (result: unknown) => GuardResult,\n\t\tlabel: string,\n\t\tisLeaveGuard: boolean,\n\t): Promise<GuardResult> {\n\t\tlet guardIndex = currentIndex;\n\t\ttry {\n\t\t\tconst result = await pendingResult;\n\t\t\tif (result !== true) return onBlock(result);\n\n\t\t\tfor (let i = currentIndex + 1; i < guards.length; i++) {\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tguardIndex = i;\n\t\t\t\tconst nextResult = await guards[i](context);\n\t\t\t\tif (nextResult !== true) return onBlock(nextResult);\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (!context.signal.aborted) {\n\t\t\t\tconst route = isLeaveGuard ? context.fromRoute : context.toRoute;\n\t\t\t\tLog.error(\n\t\t\t\t\t`${label} [${guardIndex}] on route \"${route}\" threw, navigation failed`,\n\t\t\t\t\terror instanceof Error ? error : String(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/** Validate a non-true guard result; invalid values become false. */\n\tprivate _validateGuardResult(result: unknown): GuardResult {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tif (typeof result === \"string\" && result.length > 0) return result;\n\t\tif (isGuardRedirect(result)) return result;\n\t\tLog.warning(\"Guard returned invalid value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n\n\t/** Validate a leave guard result; non-boolean values log a warning and block. */\n\tprivate _validateLeaveGuardResult(result: unknown): boolean {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tLog.warning(\"Leave guard returned non-boolean value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n}\n"],"mappings":"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","ignoreList":[]}
@@ -8,7 +8,7 @@ sap.ui.define(["sap/ui/core/Lib", "sap/ui/base/DataType", "sap/ui/core/library",
8
8
  const library = Lib.init({
9
9
  apiVersion: 2,
10
10
  name: "ui5.guard.router",
11
- version: "1.6.0",
11
+ version: "1.6.1",
12
12
  dependencies: ["sap.ui.core", "sap.m"],
13
13
  types: ["ui5.guard.router.NavigationOutcome"],
14
14
  interfaces: [],
@@ -1 +1 @@
1
- {"version":3,"file":"library-dbg.js","names":["NavigationOutcome","_interopRequireDefault","__NavigationOutcome","library","Lib","init","apiVersion","name","version","dependencies","types","interfaces","controls","elements","noLibraryCSS","DataType","registerEnum"],"sources":["library.ts"],"sourcesContent":["import Lib from \"sap/ui/core/Lib\";\nimport DataType from \"sap/ui/base/DataType\";\nimport \"sap/ui/core/library\";\nimport \"sap/m/library\";\nimport NavigationOutcome from \"./NavigationOutcome\";\n\nconst library = Lib.init({\n\tapiVersion: 2,\n\tname: \"ui5.guard.router\",\n\tversion: \"1.6.0\",\n\tdependencies: [\"sap.ui.core\", \"sap.m\"],\n\ttypes: [\"ui5.guard.router.NavigationOutcome\"],\n\tinterfaces: [],\n\tcontrols: [],\n\telements: [],\n\tnoLibraryCSS: true,\n});\n\nDataType.registerEnum(\"ui5.guard.router.NavigationOutcome\", NavigationOutcome);\n\nexport default library;\n"],"mappings":";;;;;;QAIOA,iBAAiB,GAAAC,sBAAA,CAAAC,mBAAA;EAExB,MAAMC,OAAO,GAAGC,GAAG,CAACC,IAAI,CAAC;IACxBC,UAAU,EAAE,CAAC;IACbC,IAAI,EAAE,kBAAkB;IACxBC,OAAO,EAAE,OAAO;IAChBC,YAAY,EAAE,CAAC,aAAa,EAAE,OAAO,CAAC;IACtCC,KAAK,EAAE,CAAC,oCAAoC,CAAC;IAC7CC,UAAU,EAAE,EAAE;IACdC,QAAQ,EAAE,EAAE;IACZC,QAAQ,EAAE,EAAE;IACZC,YAAY,EAAE;EACf,CAAC,CAAC;EAEFC,QAAQ,CAACC,YAAY,CAAC,oCAAoC,EAAEhB,iBAAiB,CAAC;EAAC,OAEhEG,OAAO;AAAA","ignoreList":[]}
1
+ {"version":3,"file":"library-dbg.js","names":["NavigationOutcome","_interopRequireDefault","__NavigationOutcome","library","Lib","init","apiVersion","name","version","dependencies","types","interfaces","controls","elements","noLibraryCSS","DataType","registerEnum"],"sources":["library.ts"],"sourcesContent":["import Lib from \"sap/ui/core/Lib\";\nimport DataType from \"sap/ui/base/DataType\";\nimport \"sap/ui/core/library\";\nimport \"sap/m/library\";\nimport NavigationOutcome from \"./NavigationOutcome\";\n\nconst library = Lib.init({\n\tapiVersion: 2,\n\tname: \"ui5.guard.router\",\n\tversion: \"1.6.1\",\n\tdependencies: [\"sap.ui.core\", \"sap.m\"],\n\ttypes: [\"ui5.guard.router.NavigationOutcome\"],\n\tinterfaces: [],\n\tcontrols: [],\n\telements: [],\n\tnoLibraryCSS: true,\n});\n\nDataType.registerEnum(\"ui5.guard.router.NavigationOutcome\", NavigationOutcome);\n\nexport default library;\n"],"mappings":";;;;;;QAIOA,iBAAiB,GAAAC,sBAAA,CAAAC,mBAAA;EAExB,MAAMC,OAAO,GAAGC,GAAG,CAACC,IAAI,CAAC;IACxBC,UAAU,EAAE,CAAC;IACbC,IAAI,EAAE,kBAAkB;IACxBC,OAAO,EAAE,OAAO;IAChBC,YAAY,EAAE,CAAC,aAAa,EAAE,OAAO,CAAC;IACtCC,KAAK,EAAE,CAAC,oCAAoC,CAAC;IAC7CC,UAAU,EAAE,EAAE;IACdC,QAAQ,EAAE,EAAE;IACZC,QAAQ,EAAE,EAAE;IACZC,YAAY,EAAE;EACf,CAAC,CAAC;EAEFC,QAAQ,CAACC,YAAY,CAAC,oCAAoC,EAAEhB,iBAAiB,CAAC;EAAC,OAEhEG,OAAO;AAAA","ignoreList":[]}
@@ -1,10 +1,10 @@
1
1
  //@ui5-bundle ui5/guard/router/library-preload.js
2
- sap.ui.predefine("ui5/guard/router/GuardPipeline", ["sap/base/Log"],function(r){"use strict";const e="ui5.guard.router.Router";function t(r){if(typeof r!=="object"||r===null){return false}const{route:e}=r;return typeof e==="string"&&e.length>0}function a(r){if(typeof r!=="object"&&typeof r!=="function"||r===null){return false}return typeof r.then==="function"}class n{_globalGuards=[];_enterGuards=new Map;_leaveGuards=new Map;addGlobalGuard(r){this._globalGuards.push(r)}removeGlobalGuard(r){const e=this._globalGuards.indexOf(r);if(e!==-1){this._globalGuards.splice(e,1)}}addEnterGuard(r,e){this._addToGuardMap(this._enterGuards,r,e)}removeEnterGuard(r,e){this._removeFromGuardMap(this._enterGuards,r,e)}addLeaveGuard(r,e){this._addToGuardMap(this._leaveGuards,r,e)}removeLeaveGuard(r,e){this._removeFromGuardMap(this._leaveGuards,r,e)}clear(){this._globalGuards=[];this._enterGuards.clear();this._leaveGuards.clear()}evaluate(r,e){const t=!e?.skipLeaveGuards&&r.fromRoute!==""&&this._leaveGuards.has(r.fromRoute);const n=this._globalGuards.length>0||r.toRoute!==""&&this._enterGuards.has(r.toRoute);if(!t&&!n){return{action:"allow"}}const u=r=>{if(a(r)){return r.then(r=>{if(r===true)return{action:"allow"};if(r===false)return{action:"block"};return{action:"redirect",target:r}}).catch(r=>({action:"error",error:r}))}if(r===true)return{action:"allow"};if(r===false)return{action:"block"};return{action:"redirect",target:r}};const o=()=>{const e=this._runEnterGuards(r.toRoute,r);return u(e)};try{if(t){const e=this._runLeaveGuards(r);if(a(e)){return e.then(e=>{if(e!==true)return{action:"block"};if(r.signal.aborted)return{action:"block"};return o()}).catch(r=>({action:"error",error:r}))}if(e!==true)return{action:"block"}}return o()}catch(r){return{action:"error",error:r}}}_addToGuardMap(r,e,t){let a=r.get(e);if(!a){a=[];r.set(e,a)}a.push(t)}_removeFromGuardMap(r,e,t){const a=r.get(e);if(!a)return;const n=a.indexOf(t);if(n!==-1)a.splice(n,1);if(a.length===0)r.delete(e)}_runLeaveGuards(t){const n=this._leaveGuards.get(t.fromRoute);if(!n||n.length===0)return true;const u=n.slice();for(let n=0;n<u.length;n++){try{const r=u[n](t);if(a(r)){return this._continueGuardsAsync(r,u,n,t,r=>this._validateLeaveGuardResult(r),"Leave guard",true)}if(r!==true)return this._validateLeaveGuardResult(r)}catch(a){r.error(`Leave guard [${n}] on route "${t.fromRoute}" threw, navigation failed`,String(a),e);if(t.signal.aborted)return false;throw a}}return true}_runEnterGuards(r,e){const t=this._runGuards(this._globalGuards,e);if(a(t)){return t.then(t=>{if(t!==true)return t;if(e.signal.aborted)return false;return this._runRouteGuards(r,e)})}if(t!==true)return t;return this._runRouteGuards(r,e)}_runRouteGuards(r,e){if(!r||!this._enterGuards.has(r))return true;return this._runGuards(this._enterGuards.get(r),e)}_runGuards(t,n){t=t.slice();for(let u=0;u<t.length;u++){try{const r=t[u](n);if(a(r)){return this._continueGuardsAsync(r,t,u,n,r=>this._validateGuardResult(r),"Enter guard",false)}if(r!==true)return this._validateGuardResult(r)}catch(t){r.error(`Enter guard [${u}] on route "${n.toRoute}" threw, navigation failed`,String(t),e);if(n.signal.aborted)return false;throw t}}return true}async _continueGuardsAsync(t,a,n,u,o,i,s){let l=n;try{const r=await t;if(r!==true)return o(r);for(let r=n+1;r<a.length;r++){if(u.signal.aborted)return false;l=r;const e=await a[r](u);if(e!==true)return o(e)}return true}catch(t){if(!u.signal.aborted){const a=s?u.fromRoute:u.toRoute;r.error(`${i} [${l}] on route "${a}" threw, navigation failed`,String(t),e);throw t}return false}}_validateGuardResult(a){if(typeof a==="boolean")return a;if(typeof a==="string"&&a.length>0)return a;if(t(a))return a;r.warning("Guard returned invalid value, treating as block",String(a),e);return false}_validateLeaveGuardResult(t){if(typeof t==="boolean")return t;r.warning("Leave guard returned non-boolean value, treating as block",String(t),e);return false}}n.isPromiseLike=a;return n});
2
+ sap.ui.predefine("ui5/guard/router/GuardPipeline", ["sap/base/Log"],function(r){"use strict";const e="ui5.guard.router.Router";function t(r){if(typeof r!=="object"||r===null){return false}const{route:e}=r;return typeof e==="string"&&e.length>0}function a(r){if(typeof r!=="object"&&typeof r!=="function"||r===null){return false}return typeof r.then==="function"}class n{_globalGuards=[];_enterGuards=new Map;_leaveGuards=new Map;addGlobalGuard(r){this._globalGuards.push(r)}removeGlobalGuard(r){const e=this._globalGuards.indexOf(r);if(e!==-1){this._globalGuards.splice(e,1)}}addEnterGuard(r,e){this._addToGuardMap(this._enterGuards,r,e)}removeEnterGuard(r,e){this._removeFromGuardMap(this._enterGuards,r,e)}addLeaveGuard(r,e){this._addToGuardMap(this._leaveGuards,r,e)}removeLeaveGuard(r,e){this._removeFromGuardMap(this._leaveGuards,r,e)}clear(){this._globalGuards=[];this._enterGuards.clear();this._leaveGuards.clear()}evaluate(r,e){const t=!e?.skipLeaveGuards&&r.fromRoute!==""&&this._leaveGuards.has(r.fromRoute);const n=this._globalGuards.length>0||r.toRoute!==""&&this._enterGuards.has(r.toRoute);if(!t&&!n){return{action:"allow"}}const u=r=>{if(a(r)){return r.then(r=>{if(r===true)return{action:"allow"};if(r===false)return{action:"block"};return{action:"redirect",target:r}}).catch(r=>({action:"error",error:r}))}if(r===true)return{action:"allow"};if(r===false)return{action:"block"};return{action:"redirect",target:r}};const o=()=>{const e=this._runEnterGuards(r.toRoute,r);return u(e)};try{if(t){const e=this._runLeaveGuards(r);if(a(e)){return e.then(e=>{if(e!==true)return{action:"block"};if(r.signal.aborted)return{action:"block"};return o()}).catch(r=>({action:"error",error:r}))}if(e!==true)return{action:"block"}}return o()}catch(r){return{action:"error",error:r}}}_addToGuardMap(r,e,t){let a=r.get(e);if(!a){a=[];r.set(e,a)}a.push(t)}_removeFromGuardMap(r,e,t){const a=r.get(e);if(!a)return;const n=a.indexOf(t);if(n!==-1)a.splice(n,1);if(a.length===0)r.delete(e)}_runLeaveGuards(t){const n=this._leaveGuards.get(t.fromRoute);if(!n||n.length===0)return true;const u=n.slice();for(let n=0;n<u.length;n++){try{const r=u[n](t);if(a(r)){return this._continueGuardsAsync(r,u,n,t,r=>this._validateLeaveGuardResult(r),"Leave guard",true)}if(r!==true)return this._validateLeaveGuardResult(r)}catch(a){r.error(`Leave guard [${n}] on route "${t.fromRoute}" threw, navigation failed`,a instanceof Error?a:String(a),e);if(t.signal.aborted)return false;throw a}}return true}_runEnterGuards(r,e){const t=this._runGuards(this._globalGuards,e);if(a(t)){return t.then(t=>{if(t!==true)return t;if(e.signal.aborted)return false;return this._runRouteGuards(r,e)})}if(t!==true)return t;return this._runRouteGuards(r,e)}_runRouteGuards(r,e){if(!r||!this._enterGuards.has(r))return true;return this._runGuards(this._enterGuards.get(r),e)}_runGuards(t,n){t=t.slice();for(let u=0;u<t.length;u++){try{const r=t[u](n);if(a(r)){return this._continueGuardsAsync(r,t,u,n,r=>this._validateGuardResult(r),"Enter guard",false)}if(r!==true)return this._validateGuardResult(r)}catch(t){r.error(`Enter guard [${u}] on route "${n.toRoute}" threw, navigation failed`,t instanceof Error?t:String(t),e);if(n.signal.aborted)return false;throw t}}return true}async _continueGuardsAsync(t,a,n,u,o,i,s){let l=n;try{const r=await t;if(r!==true)return o(r);for(let r=n+1;r<a.length;r++){if(u.signal.aborted)return false;l=r;const e=await a[r](u);if(e!==true)return o(e)}return true}catch(t){if(!u.signal.aborted){const a=s?u.fromRoute:u.toRoute;r.error(`${i} [${l}] on route "${a}" threw, navigation failed`,t instanceof Error?t:String(t),e);throw t}return false}}_validateGuardResult(a){if(typeof a==="boolean")return a;if(typeof a==="string"&&a.length>0)return a;if(t(a))return a;r.warning("Guard returned invalid value, treating as block",String(a),e);return false}_validateLeaveGuardResult(t){if(typeof t==="boolean")return t;r.warning("Leave guard returned non-boolean value, treating as block",String(t),e);return false}}n.isPromiseLike=a;return n});
3
3
  sap.ui.predefine("ui5/guard/router/NavigationOutcome", [],function(){"use strict";const e=Object.freeze({Committed:"committed",Bypassed:"bypassed",Blocked:"blocked",Redirected:"redirected",Cancelled:"cancelled",Error:"error"});return e});
4
4
  sap.ui.predefine("ui5/guard/router/Router", ["sap/m/routing/Router","sap/base/Log","sap/ui/core/library","./NavigationOutcome","./GuardPipeline"],function(t,e,i,n,r){"use strict";function s(t){return t&&t.__esModule&&typeof t.default!=="undefined"?t.default:t}const o=s(n);const a=s(r);const u=r["isPromiseLike"];const h=i.routing.HistoryDirection;const c="ui5.guard.router.Router";function d(t){return typeof t==="object"&&t!==null}const f={kind:"idle"};function l(t){if(typeof t!=="object"||t===null||Array.isArray(t))return false;const e=Object.getPrototypeOf(t);return e===Object.prototype||e===null}function p(...t){const e=new Set(t);return t=>typeof t==="string"&&e.has(t)}const g=p("ignore","warn","throw");const _=p("guard","bypass","off");const m=p("block","lazy");const v=p("none","pattern-tree");const y=/^:[^:]*\*?:$/;function R(t){const e=t.indexOf("{?");if(e!==-1)return t.slice(0,e);const i=t.indexOf(":?");if(i!==-1)return t.slice(0,i);return t}function b(t){return t.split("/").map(R).filter(t=>t!==""&&!y.test(t))}function k(t,e){if(t==="")return true;const i=b(t);if(i.length===0)return false;const n=b(e);if(n.length<=i.length)return false;return i.every((t,e)=>{const i=n[e];if(t===i)return true;return t.startsWith("{")&&i.startsWith("{")})}function G(t,e){if(t.startsWith("module:")){return t.slice("module:".length).replace(/\./g,"/")}const i=e?e+"."+t:t;return i.replace(/\./g,"/")}function w(t,e){const i=t.indexOf("#");const n=i===-1?t:t.slice(0,i);const r=i===-1?undefined:t.slice(i+1);const s=G(n,e);const o=n.split(".").pop()??n;const a=r??o;return{modulePath:s,name:a,exportKey:r}}function M(t,i){e.warning(`guardRouter.guards: "${t}" ${i}`,undefined,c)}function H(t,i,n,r){const s=i.split("/").pop()??i;if(typeof t==="function"){if(r!==undefined){e.debug(`guardRouter.guards: "${i}#${r}" is a single function, ignoring export key`,undefined,c)}return[{name:n,fn:t}]}if(Array.isArray(t)){if(t.length===0){M(i,"exported an empty array, skipping");return[]}if(r!==undefined){const e=parseInt(r,10);if(Number.isNaN(e)||e<0||e>=t.length){M(i,`#${r} - index out of range, skipping`);return[]}const n=t[e];if(typeof n!=="function"){M(i,`#${r} is not a function, skipping`);return[]}return[{name:`${s}#${r}`,fn:n}]}const e=[];for(let n=0;n<t.length;n++){const r=t[n];if(typeof r!=="function"){M(i,`[${n}] is not a function, skipping`);continue}e.push({name:`${s}#${n}`,fn:r})}return e}if(l(t)){const e=Object.entries(t);if(e.length===0){M(i,"exported an empty object, skipping");return[]}if(r!==undefined){let n=t[r];let s=r;if(n===undefined){const t=parseInt(r,10);if(!Number.isNaN(t)&&t>=0&&t<e.length){const[i,r]=e[t];n=r;s=i}}if(n===undefined){M(i,`#${r} - key not found, skipping`);return[]}if(typeof n!=="function"){M(i,`#${r} is not a function, skipping`);return[]}return[{name:s,fn:n}]}const n=[];for(const[t,r]of e){if(typeof r!=="function"){M(i,`.${t} is not a function, skipping`);continue}n.push({name:t,fn:r})}return n}M(i,"did not export a function, array, or plain object, skipping");return[]}function N(t,i){if(!l(t)){e.warning("guardRouter.guards is not a plain object, skipping",JSON.stringify(t),c);return[]}const n=[];function r(t,r,s,o){for(const a of t){if(typeof a!=="string"||a.length===0){e.warning(`guardRouter.guards${o}: invalid entry, skipping`,JSON.stringify(a),c);continue}const t=w(a,i);n.push({route:r,type:s,...t})}}for(const[i,n]of Object.entries(t)){if(Array.isArray(n)){r(n,i,"enter",`["${i}"]`)}else if(l(n)){const t=n;if(i==="*"&&t.leave!==undefined){e.warning('guardRouter.guards["*"].leave: global leave guards are not supported, skipping',undefined,c)}if(i==="*"&&t.enter===undefined&&t.leave!==undefined){continue}if(i==="*"&&t.enter!==undefined){e.info('guardRouter.guards["*"]: object form; treating enter as global',undefined,c)}if(Array.isArray(t.enter)){r(t.enter,i,"enter",`["${i}"].enter`)}if(i!=="*"&&Array.isArray(t.leave)){r(t.leave,i,"leave",`["${i}"].leave`)}}else{e.warning(`guardRouter.guards["${i}"]: expected string[] or { enter?, leave? }, skipping`,JSON.stringify(n),c)}}return n}const P={unknownRouteRegistration:"warn",navToPreflight:"guard",guardLoading:"lazy",inheritance:"none"};function S(t,i,n,r){if(t[i]!==undefined){if(n(t[i])){r[i]=t[i]}else{e.warning(`guardRouter.${i} has invalid value, using default`,JSON.stringify(t[i]),c)}}}function $(t){if(!l(t)){if(t!==undefined){e.warning("guardRouter config is not a plain object, using defaults",JSON.stringify(t),c)}return P}const i={...P};S(t,"unknownRouteRegistration",g,i);S(t,"navToPreflight",_,i);S(t,"guardLoading",m,i);S(t,"inheritance",v,i);return i}const T=10;const D=t.extend("ui5.guard.router.Router",{constructor:function i(...n){const[r,s,o,...u]=n;const h=s;const d=l(h);const{guardRouter:p,...g}=d?h:{};t.prototype.constructor.apply(this,[r,d?g:s,o,...u]);this._options=P;this._pipeline=new a;this._currentRoute="";this._currentHash=null;this._phase=f;this._parseGeneration=0;this._suppressedHash=null;this._settlementResolvers=[];this._lastSettlement=null;this._pendingGuardDescriptors=[];this._sourceDescriptors=[];this._destroyed=false;this._manifestMeta=new Map;this._runtimeMeta=new Map;this._resolvedMetaCache=new Map;this._routeNames=[];this._options=$(p);if(Array.isArray(r)){this._routeNames=r.filter(t=>l(t)&&typeof t.name==="string").map(t=>t.name)}else if(l(r)){this._routeNames=Object.keys(r)}if(l(p)&&p.routeMeta!==undefined){if(l(p.routeMeta)){for(const[t,i]of Object.entries(p.routeMeta)){if(l(i)){this._manifestMeta.set(t,Object.freeze({...i}))}else{e.warning(`guardRouter.routeMeta["${t}"]: expected object, skipping`,JSON.stringify(i),c)}}}else{e.warning("guardRouter.routeMeta: expected object, skipping",JSON.stringify(p.routeMeta),c)}}if(l(p)&&p.guards!==undefined){let t="";if(o){const e=o.getManifestEntry("sap.app");if(l(e)&&typeof e.id==="string"){t=e.id}}this._pendingGuardDescriptors=N(p.guards,t);if(this._pendingGuardDescriptors.length>0&&this._options.guardLoading==="lazy"){const t=[...new Set(this._pendingGuardDescriptors.map(t=>t.modulePath))];sap.ui.require(t)}}},initialize:function i(){if(this._pendingGuardDescriptors.length===0){return t.prototype.initialize.call(this)}const n=this._pendingGuardDescriptors;this._pendingGuardDescriptors=[];this._sourceDescriptors=n;const r=this._options.inheritance==="pattern-tree"?this._expandGuardDescriptors(n):n;if(this._options.guardLoading==="lazy"){this._registerLazyGuards(r);return t.prototype.initialize.call(this)}this._loadAndRegisterGuards(r).then(()=>{if(!this._destroyed)t.prototype.initialize.call(this)}).catch(i=>{if(this._destroyed)return;e.error("guardRouter.guards: module loading failed, initializing without manifest guards",String(i),c);t.prototype.initialize.call(this)});return this},addRoute:function e(i,...n){t.prototype.addRoute.apply(this,[i,...n]);if(!this._routeNames)return;const r=i.name;if(typeof r!=="string")return;if(this._routeNames.includes(r))return;this._routeNames.push(r);this._resolvedMetaCache.clear();if(this._options.inheritance!=="pattern-tree")return;if(this._sourceDescriptors.length===0)return;const s=this.getRoute(r);if(!s)return;const o=s.getPattern();if(o===undefined)return;const a=this._expandGuardDescriptorsForNewRoute(r,o);if(a.length===0)return;this._registerLazyGuards(a)},_expandGuardDescriptorsForNewRoute:function t(e,i){const n=[];for(const t of this._sourceDescriptors){if(t.route==="*")continue;if(t.route!==e){const r=this.getRoute(t.route);const s=r?.getPattern();if(s!==undefined&&k(s,i)){n.push({...t,route:e})}}else{for(const{name:r,pattern:s}of this._collectRoutePatterns()){if(r===e)continue;if(k(i,s)){n.push({...t,route:r})}}}}return n.toSorted((t,e)=>{const i=this.getRoute(t.route)?.getPattern()??"";const n=this.getRoute(e.route)?.getPattern()??"";return b(i).length-b(n).length})},addGuard:function t(e){if(!this._isFn(e,"addGuard"))return this;this._pipeline.addGlobalGuard(e);return this},removeGuard:function t(e){if(!this._isFn(e,"removeGuard"))return this;this._pipeline.removeGlobalGuard(e);return this},addRouteGuard:function t(i,n){if(d(n)){if(!this._handleUnknownRouteRegistration(i,"addRouteGuard")){return this}let t=false;if(n.beforeEnter!==undefined){t=true;if(this._isFn(n.beforeEnter,"addRouteGuard",i)){this._pipeline.addEnterGuard(i,n.beforeEnter)}}if(n.beforeLeave!==undefined){t=true;if(this._isFn(n.beforeLeave,"addRouteGuard",i)){this._pipeline.addLeaveGuard(i,n.beforeLeave)}}if(!t){e.info("addRouteGuard: config has no beforeEnter or beforeLeave",i,c);return this}return this}if(!this._isFn(n,"addRouteGuard",i))return this;if(!this._handleUnknownRouteRegistration(i,"addRouteGuard")){return this}this._pipeline.addEnterGuard(i,n);return this},removeRouteGuard:function t(e,i){if(d(i)){if(typeof i.beforeEnter==="function"){this.removeRouteGuard(e,i.beforeEnter)}if(typeof i.beforeLeave==="function"){this.removeLeaveGuard(e,i.beforeLeave)}return this}if(!this._isFn(i,"removeRouteGuard",e))return this;this._pipeline.removeEnterGuard(e,i);return this},addLeaveGuard:function t(e,i){if(!this._isFn(i,"addLeaveGuard",e))return this;if(!this._handleUnknownRouteRegistration(e,"addLeaveGuard")){return this}this._pipeline.addLeaveGuard(e,i);return this},_resolveNavToArgs:function t(e,i,n){if(typeof e==="boolean"){return{replace:e,guardOptions:typeof i==="object"&&i!==null?i:undefined}}return{componentTargetInfo:e,replace:typeof i==="boolean"?i:undefined,guardOptions:n}},_isFn:function t(i,n,r){if(typeof i==="function")return true;e.warning(`${n}: not a function, ignoring`,r,c);return false},_handleUnknownRouteRegistration:function t(i,n){if(this.getRoute(i))return true;switch(this._options.unknownRouteRegistration){case"ignore":return true;case"throw":throw new Error(`${n} called for unknown route "${i}". `+`Set guardRouter.unknownRouteRegistration to "warn" or "ignore" to allow this.`);case"warn":default:e.warning(`${n}: unknown route, guard registered anyway`,i,c);return true}},removeLeaveGuard:function t(e,i){if(!this._isFn(i,"removeLeaveGuard",e))return this;this._pipeline.removeLeaveGuard(e,i);return this},getRouteMeta:function t(i){if(i!==""&&!this.getRoute(i)){e.warning("getRouteMeta: unknown route, returning empty metadata",i,c);return D._EMPTY_META}const n=this._resolvedMetaCache.get(i);if(n)return n;let r;if(this._options.inheritance==="pattern-tree"){r=this._resolveInheritedMeta(i)}else{r=this._resolveFlatMeta(i)}if(Object.keys(r).length===0){this._resolvedMetaCache.set(i,D._EMPTY_META);return D._EMPTY_META}this._resolvedMetaCache.set(i,r);return r},setRouteMeta:function t(i,n){if(!l(n)){e.warning("setRouteMeta: expected object, ignoring",i,c);return this}if(i!==""&&!this._handleUnknownRouteRegistration(i,"setRouteMeta")){return this}this._runtimeMeta.set(i,Object.freeze({...n}));this._resolvedMetaCache.clear();return this},navigationSettled:function t(){if(this._phase.kind!=="evaluating"){return Promise.resolve(this._lastSettlement??{status:o.Committed,route:this._currentRoute,hash:this._currentHash??""})}return new Promise(t=>{this._settlementResolvers.push(t)})},attachNavigationSettled:function t(e,i,n){this.attachEvent("navigationSettled",e,i,n);return this},detachNavigationSettled:function t(e,i){this.detachEvent("navigationSettled",e,i);return this},_flushSettlement:function t(e){this._lastSettlement=e;const i=this._settlementResolvers;this._settlementResolvers=[];for(const t of i){t(e)}this.fireEvent("navigationSettled",e)},navTo:function i(n,r,s,o,a){const{componentTargetInfo:h,replace:d,guardOptions:f}=this._resolveNavToArgs(s,o,a);if(this._phase.kind==="committing"&&this._phase.origin==="redirect"){t.prototype.navTo.call(this,n,r,h,d);return this}const l=this.getRoute(n);if(!l){this._cancelPendingNavigation();t.prototype.navTo.call(this,n,r,h,d);return this}const p=l.getURL(r??{});const g=this.getRouteInfoByHash(p);const _=g?.name??"";if(this._currentHash!==null&&p===this._currentHash){this._cancelPendingNavigation();return this}if(this._phase.kind==="evaluating"&&p===this._phase.attempt.hash){return this}this._cancelPendingNavigation();const m=f?.skipGuards===true;if(m||this._options.navToPreflight==="bypass"){this._phase={kind:"committing",hash:p,route:_,origin:"preflight"};t.prototype.navTo.call(this,n,r,h,d);if(this._phase.kind==="committing"&&this._phase.hash===p){this._commitNavigation(p,_)}return this}if(this._options.navToPreflight==="off"){t.prototype.navTo.call(this,n,r,h,d);return this}const v=new AbortController;const y=this._parseGeneration;this._phase={kind:"evaluating",attempt:{hash:p,route:_,controller:v,generation:y}};const R=this._createGuardContext(_,p,g,v.signal);const b=this._pipeline.evaluate(R);if(u(b)){b.then(t=>{if(y!==this._parseGeneration||this._phase.kind!=="evaluating"){e.debug("Async preflight result discarded (superseded by newer navigation)",p,c);return}this._applyPreflightDecision(t,n,r,h,d,p,_,R.bag)}).catch(t=>{if(y!==this._parseGeneration)return;e.error(`Async preflight guard failed for route "${n}", navigation failed`,String(t),c);this._errorNavigation(t,p,false)});return this}this._applyPreflightDecision(b,n,r,h,d,p,_,R.bag);return this},_applyPreflightDecision:function e(i,n,r,s,o,a,u,h){switch(i.action){case"allow":this._phase={kind:"committing",hash:a,route:u,origin:"preflight"};t.prototype.navTo.call(this,n,r,s,o);if(this._phase.kind==="committing"&&this._phase.hash===a){this._commitNavigation(a,u)}break;case"block":this._blockNavigation(a,false);break;case"redirect":this._startRedirectChain(i.target,a,false,h);break;case"error":this._errorNavigation(i.error,a,false);break}},parse:function t(i){if(this._suppressedHash!==null){if(i===this._suppressedHash){this._suppressedHash=null;return}this._suppressedHash=null}if(this._phase.kind==="committing"){this._commitNavigation(i,this._phase.route!==""?this._phase.route:this.getRouteInfoByHash(i)?.name??"");return}if(this._currentHash!==null&&i===this._currentHash){this._cancelPendingNavigation();return}const n=this.getRouteInfoByHash(i);const r=n?.name??"";this._cancelPendingNavigation();const s=new AbortController;const o=this._parseGeneration;this._phase={kind:"evaluating",attempt:{hash:i,route:r,controller:s,generation:o}};const a=this._createGuardContext(r,i,n,s.signal);const h=this._pipeline.evaluate(a);if(u(h)){h.then(t=>{if(o!==this._parseGeneration||this._phase.kind!=="evaluating"){e.debug("Async guard result discarded (superseded by newer navigation)",i,c);return}this._applyDecision(t,i,r,a.bag)}).catch(t=>{if(o!==this._parseGeneration)return;e.error(`Guard pipeline failed for "${i}", navigation failed`,String(t),c);this._errorNavigation(t,i)});return}this._applyDecision(h,i,r,a.bag)},stop:function e(){this._cancelPendingNavigation();this._suppressedHash=null;this._currentRoute="";this._currentHash=null;this._lastSettlement=null;t.prototype.stop.call(this);return this},_cancelPendingNavigation:function t(){++this._parseGeneration;if(this._phase.kind==="evaluating"){this._phase.attempt.controller.abort();this._flushSettlement({status:o.Cancelled,route:this._currentRoute,hash:this._currentHash??""})}this._phase=f},_applyDecision:function t(e,i,n,r){switch(e.action){case"allow":this._phase={kind:"committing",hash:i,route:n,origin:"parse"};this._commitNavigation(i,n);break;case"block":this._blockNavigation(i);break;case"redirect":this._startRedirectChain(e.target,i,true,r);break;case"error":this._errorNavigation(e.error,i);break}},_commitNavigation:function e(i,n){const r=this._phase.kind==="committing"&&this._phase.origin==="redirect";this._currentHash=i;this._currentRoute=n??this.getRouteInfoByHash(i)?.name??"";this._phase=f;this._flushSettlement({status:r?o.Redirected:this._currentRoute===""?o.Bypassed:o.Committed,route:this._currentRoute,hash:i});t.prototype.parse.call(this,i)},_redirect:function t(i,n){const r=typeof i==="string"?i:i.route;let s=null;const o=typeof i==="string"?{}:i.parameters??{};const a=this.getRoute(r);if(a){try{s=a.getURL(o)}catch{s=null}}if(s!==null&&n.visited.has(s)){e.error(`Guard redirect loop detected: ${[...n.visited,s].join(" -> ")}`,undefined,c);this._blockNavigation(n.attemptedHash,n.restoreHash);return}if(n.visited.size>T){e.error(`Guard redirect chain exceeded maximum depth (${T}): ${[...n.visited].join(" -> ")}`,undefined,c);this._blockNavigation(n.attemptedHash,n.restoreHash);return}if(s!==null){n.visited.add(s)}if(s===null){const t=this._lastSettlement;this._phase={kind:"committing",hash:"",route:r,origin:"redirect"};try{if(typeof i==="string"){this.navTo(i,{},{},true)}else{this.navTo(i.route,i.parameters??{},i.componentTargetInfo,true)}}finally{if(this._phase.kind==="committing"){this._phase=f}}if(this._lastSettlement===t){e.warning(`Guard redirect target "${r}" did not produce a navigation, treating as blocked`,undefined,c);this._blockNavigation(n.attemptedHash,n.restoreHash)}return}const h=s;const d=this.getRouteInfoByHash(h);const l={toRoute:d?.name??"",toHash:h,toArguments:d?.arguments??{},fromRoute:n.fromRoute,fromHash:n.fromHash,signal:n.signal,bag:n.bag,toMeta:this.getRouteMeta(d?.name??""),fromMeta:this.getRouteMeta(n.fromRoute)};const p=this._pipeline.evaluate(l,{skipLeaveGuards:true});if(u(p)){p.then(t=>{if(n.generation!==this._parseGeneration)return;this._applyRedirectDecision(t,i,h,n)}).catch(t=>{if(n.generation!==this._parseGeneration)return;e.error(`Guard pipeline failed during redirect chain for "${r}", navigation failed`,String(t),c);this._errorNavigation(t,n.attemptedHash,n.restoreHash)});return}this._applyRedirectDecision(p,i,h,n)},_applyRedirectDecision:function t(i,n,r,s){switch(i.action){case"allow":{const t=typeof n==="string"?n:n.route;const i=this._lastSettlement;this._phase={kind:"committing",hash:r,route:t,origin:"redirect"};try{if(typeof n==="string"){this.navTo(n,{},{},true)}else{this.navTo(n.route,n.parameters??{},n.componentTargetInfo,true)}}finally{if(this._phase.kind==="committing"){this._phase=f}}if(this._lastSettlement===i){const i=r===(this._currentHash??"");if(i){this._phase={kind:"committing",hash:this._currentHash??"",route:this._currentRoute,origin:"redirect"};this._commitNavigation(this._currentHash??"",this._currentRoute);return}e.warning(`Guard redirect target "${t}" did not produce a navigation, treating as blocked`,undefined,c);this._blockNavigation(s.attemptedHash,s.restoreHash)}break}case"block":this._blockNavigation(s.attemptedHash,s.restoreHash);break;case"redirect":this._redirect(i.target,s);break;case"error":this._errorNavigation(i.error,s.attemptedHash,s.restoreHash);break}},_createGuardContext:function t(e,i,n,r){return{toRoute:e,toHash:i,toArguments:n?.arguments??{},fromRoute:this._currentRoute,fromHash:this._currentHash??"",signal:r,bag:new Map,toMeta:this.getRouteMeta(e),fromMeta:this.getRouteMeta(this._currentRoute)}},_startRedirectChain:function t(e,i,n,r){const{attempt:s}=this._phase;const o=new Set;o.add(i);this._redirect(e,{visited:o,attemptedHash:i,restoreHash:n,fromRoute:this._currentRoute,fromHash:this._currentHash??"",signal:s.controller.signal,generation:s.generation,bag:r})},_blockNavigation:function t(e,i=true){this._phase=f;this._flushSettlement({status:o.Blocked,route:this._currentRoute,hash:this._currentHash??""});this._restoreHashIfNeeded(e,i)},_errorNavigation:function t(e,i,n=true){this._phase=f;this._flushSettlement({status:o.Error,route:this._currentRoute,hash:this._currentHash??"",error:e});this._restoreHashIfNeeded(i,n)},_restoreHashIfNeeded:function t(e,i){if(!i)return;if(this._currentHash===null&&e&&e!==""){this._restoreHash("",false);return}this._restoreHash(this._currentHash??"")},_restoreHash:function t(e,i=true){const n=this.getHashChanger();if(n){this._suppressedHash=i?e:null;n.replaceHash(e,h.Unknown);if(this._suppressedHash===e){this._suppressedHash=null}}},_collectRoutePatterns:function t(){const e=[];for(const t of this._routeNames){const i=this.getRoute(t);if(i){const n=i.getPattern();if(n!==undefined){e.push({name:t,pattern:n})}}}return e},_expandGuardDescriptors:function t(e){const i=this._collectRoutePatterns();if(i.length===0)return e;const n=new Map(i.map(t=>[t.name,t.pattern]));const r=[];for(const t of e){r.push(t);if(t.route==="*")continue;const e=n.get(t.route);if(e===undefined)continue;for(const{name:n,pattern:s}of i){if(n===t.route)continue;if(k(e,s)){r.push({...t,route:n})}}}return r.sort((t,e)=>{if(t.route==="*"||e.route==="*")return 0;const i=n.get(t.route)??"";const r=n.get(e.route)??"";return b(i).length-b(r).length})},_resolveFlatMeta:function t(e){const i=this._manifestMeta.get(e);const n=this._runtimeMeta.get(e);if(!i&&!n)return D._EMPTY_META;if(!n)return i??D._EMPTY_META;if(!i)return Object.freeze({...n});return Object.freeze({...i,...n})},_resolveInheritedMeta:function t(e){const i=this._collectRoutePatterns();const n=i.find(t=>t.name===e);if(!n)return this._resolveFlatMeta(e);const r=i.filter(t=>t.name!==e&&(this._manifestMeta.has(t.name)||this._runtimeMeta.has(t.name))&&k(t.pattern,n.pattern));r.sort((t,e)=>b(t.pattern).length-b(e.pattern).length);const s={};for(const t of r){const e=this._manifestMeta.get(t.name);if(e)Object.assign(s,e);const i=this._runtimeMeta.get(t.name);if(i)Object.assign(s,i)}const o=this._manifestMeta.get(e);if(o)Object.assign(s,o);const a=this._runtimeMeta.get(e);if(a)Object.assign(s,a);if(Object.keys(s).length===0)return D._EMPTY_META;return Object.freeze(s)},_loadAndRegisterGuards:function t(i){const n=i.map(t=>new Promise(i=>{sap.ui.require([t.modulePath],e=>{i({descriptor:t,moduleExport:e})},n=>{e.warning(`guardRouter.guards: failed to load module "${t.modulePath}", skipping`,String(n),c);i({descriptor:t,moduleExport:null})})}));return Promise.all(n).then(t=>{for(const{descriptor:i,moduleExport:n}of t){if(n===null)continue;const t=H(n,i.modulePath,i.name,i.exportKey);for(const{fn:n}of t){try{this._registerGuardFromDescriptor(i,n)}catch(t){e.error(`guardRouter.guards: failed to register "${i.modulePath}"`,String(t),c)}}}})},_registerGuardFromDescriptor:function t(e,i){if(e.route==="*"){this.addGuard(i)}else if(e.type==="leave"){if(!this._handleUnknownRouteRegistration(e.route,"addLeaveGuard"))return;this._pipeline.addLeaveGuard(e.route,i)}else{this.addRouteGuard(e.route,i)}},_registerLazyGuards:function t(i){for(const t of i){const{modulePath:i,exportKey:n,name:r}=t;if(n!==undefined){const s=t=>{const s=sap.ui.require(i);if(s!==undefined){const e=H(s,i,r,n);if(e.length===0)return true;return e[0].fn(t)}return new Promise((s,o)=>{sap.ui.require([i],e=>{const o=H(e,i,r,n);if(o.length===0){s(true);return}s(o[0].fn(t))},t=>{e.warning(`guardRouter.guards: lazy load of "${i}" failed`,String(t),c);o(t)})})};this._registerGuardFromDescriptor(t,s);continue}const s=sap.ui.require(i);if(s!==undefined){const e=H(s,i,r);for(const i of e){this._registerGuardFromDescriptor(t,i.fn)}continue}let o=false;const a=n=>new Promise((s,a)=>{sap.ui.require([i],e=>{const a=H(e,i,r);if(a.length===0){s(true);return}if(!o){o=true;for(let e=1;e<a.length;e++){this._registerGuardFromDescriptor(t,a[e].fn)}}s(a[0].fn(n))},t=>{e.warning(`guardRouter.guards: lazy load of "${i}" failed`,String(t),c);a(t)})});this._registerGuardFromDescriptor(t,a)}},destroy:function e(){this._destroyed=true;this._pipeline.clear();this._pendingGuardDescriptors=[];this._sourceDescriptors=[];this._cancelPendingNavigation();this._suppressedHash=null;this._lastSettlement=null;this._manifestMeta.clear();this._runtimeMeta.clear();this._resolvedMetaCache.clear();t.prototype.destroy.call(this);return this}});D._EMPTY_META=Object.freeze({});return D});
5
- sap.ui.predefine("ui5/guard/router/library", ["sap/ui/core/Lib","sap/ui/base/DataType","sap/ui/core/library","sap/m/library","./NavigationOutcome"],function(e,i,r,t,u){"use strict";function a(e){return e&&e.__esModule&&typeof e.default!=="undefined"?e.default:e}const n=a(u);const o=e.init({apiVersion:2,name:"ui5.guard.router",version:"1.6.0",dependencies:["sap.ui.core","sap.m"],types:["ui5.guard.router.NavigationOutcome"],interfaces:[],controls:[],elements:[],noLibraryCSS:true});i.registerEnum("ui5.guard.router.NavigationOutcome",n);return o});
5
+ sap.ui.predefine("ui5/guard/router/library", ["sap/ui/core/Lib","sap/ui/base/DataType","sap/ui/core/library","sap/m/library","./NavigationOutcome"],function(e,i,r,t,u){"use strict";function a(e){return e&&e.__esModule&&typeof e.default!=="undefined"?e.default:e}const n=a(u);const o=e.init({apiVersion:2,name:"ui5.guard.router",version:"1.6.1",dependencies:["sap.ui.core","sap.m"],types:["ui5.guard.router.NavigationOutcome"],interfaces:[],controls:[],elements:[],noLibraryCSS:true});i.registerEnum("ui5.guard.router.NavigationOutcome",n);return o});
6
6
  sap.ui.require.preload({
7
- "ui5/guard/router/manifest.json":'{"_version":"2.0.0","sap.app":{"id":"ui5.guard.router","type":"library","applicationVersion":{"version":"1.6.0"},"title":"UI5 Router extension with async navigation guards","description":"Extends sap.m.routing.Router with async navigation guards, running before route matching begins."},"sap.ui":{"technology":"UI5","deviceTypes":{"desktop":true,"tablet":true,"phone":true}},"sap.ui5":{"contentDensities":{"compact":true,"cozy":true},"dependencies":{"minUI5Version":"1.144.0","libs":{"sap.ui.core":{},"sap.m":{}}}}}',
7
+ "ui5/guard/router/manifest.json":'{"_version":"2.0.0","sap.app":{"id":"ui5.guard.router","type":"library","applicationVersion":{"version":"1.6.1"},"title":"UI5 Router extension with async navigation guards","description":"Extends sap.m.routing.Router with async navigation guards, running before route matching begins."},"sap.ui":{"technology":"UI5","deviceTypes":{"desktop":true,"tablet":true,"phone":true}},"sap.ui5":{"contentDensities":{"compact":true,"cozy":true},"dependencies":{"minUI5Version":"1.144.0","libs":{"sap.ui.core":{},"sap.m":{}}}}}',
8
8
  "ui5/guard/router/types.js":function(){
9
9
 
10
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"library-preload.js","sections":[{"offset":{"line":1,"column":0},"map":{"version":3,"names":["LOG_COMPONENT","isGuardRedirect","value","route","length","isPromiseLike","then","GuardPipeline","_globalGuards","_enterGuards","Map","_leaveGuards","addGlobalGuard","guard","this","push","removeGlobalGuard","index","indexOf","splice","addEnterGuard","_addToGuardMap","removeEnterGuard","_removeFromGuardMap","addLeaveGuard","removeLeaveGuard","clear","evaluate","context","options","hasLeaveGuards","skipLeaveGuards","fromRoute","has","hasEnterGuards","toRoute","action","processEnterResult","enterResult","r","target","catch","error","runEnterPhase","_runEnterGuards","leaveResult","_runLeaveGuards","allowed","signal","aborted","map","key","guards","get","set","delete","registered","slice","i","result","_continueGuardsAsync","candidate","_validateLeaveGuardResult","Log","String","globalResult","_runGuards","_runRouteGuards","_validateGuardResult","pendingResult","currentIndex","onBlock","label","isLeaveGuard","guardIndex","nextResult","warning"],"sources":["GuardPipeline.ts"],"sourcesContent":["import Log from \"sap/base/Log\";\nimport type { GuardFn, GuardContext, GuardResult, GuardRedirect } from \"./types\";\n\nconst LOG_COMPONENT = \"ui5.guard.router.Router\";\n\nfunction isGuardRedirect(value: unknown): value is GuardRedirect {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst { route } = value as GuardRedirect;\n\treturn typeof route === \"string\" && route.length > 0;\n}\n\n/**\n * Promises/A+ thenable detection via duck typing.\n *\n * We intentionally do not use `instanceof Promise` because that misses\n * cross-realm Promises and PromiseLike/thenable objects.\n */\nexport function isPromiseLike<T>(value: unknown): value is PromiseLike<T> {\n\tif ((typeof value !== \"object\" && typeof value !== \"function\") || value === null) {\n\t\treturn false;\n\t}\n\n\treturn typeof (value as PromiseLike<T>).then === \"function\";\n}\n\n/**\n * Normalized result of the guard decision pipeline.\n */\nexport type GuardDecision =\n\t| { action: \"allow\" }\n\t| { action: \"block\" }\n\t| { action: \"redirect\"; target: string | GuardRedirect }\n\t| { action: \"error\"; error: unknown };\n\n/**\n * Standalone guard evaluation pipeline.\n *\n * Owns guard storage (global, enter, leave) and runs the full\n * leave -> global-enter -> route-enter pipeline. Pure logic with\n * no dependency on Router state beyond the current route name\n * passed into evaluate().\n *\n * @namespace ui5.guard.router\n */\nexport default class GuardPipeline {\n\tprivate _globalGuards: GuardFn[] = [];\n\tprivate _enterGuards = new Map<string, GuardFn[]>();\n\tprivate _leaveGuards = new Map<string, GuardFn[]>();\n\n\t/** Register a guard that runs for every navigation. */\n\taddGlobalGuard(guard: GuardFn): void {\n\t\tthis._globalGuards.push(guard);\n\t}\n\n\t/** Remove a previously registered global guard by reference. */\n\tremoveGlobalGuard(guard: GuardFn): void {\n\t\tconst index = this._globalGuards.indexOf(guard);\n\t\tif (index !== -1) {\n\t\t\tthis._globalGuards.splice(index, 1);\n\t\t}\n\t}\n\n\t/**\n\t * Register an enter guard for a specific route.\n\t *\n\t * @param route - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function to register.\n\t */\n\taddEnterGuard(route: string, guard: GuardFn): void {\n\t\tthis._addToGuardMap(this._enterGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove a previously registered enter guard by reference.\n\t *\n\t * @param route - Route name.\n\t * @param guard - Guard function to remove.\n\t */\n\tremoveEnterGuard(route: string, guard: GuardFn): void {\n\t\tthis._removeFromGuardMap(this._enterGuards, route, guard);\n\t}\n\n\t/**\n\t * Register a leave guard for a specific route.\n\t *\n\t * Accepts `GuardFn` to support manifest-declared guards loaded from\n\t * untyped modules. Non-boolean return values are caught at runtime\n\t * by {@link _validateLeaveGuardResult}.\n\t *\n\t * @param route - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function to register as a leave guard.\n\t */\n\taddLeaveGuard(route: string, guard: GuardFn): void {\n\t\tthis._addToGuardMap(this._leaveGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove a previously registered leave guard by reference.\n\t *\n\t * @param route - Route name.\n\t * @param guard - Guard function to remove.\n\t */\n\tremoveLeaveGuard(route: string, guard: GuardFn): void {\n\t\tthis._removeFromGuardMap(this._leaveGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove all registered guards.\n\t */\n\tclear(): void {\n\t\tthis._globalGuards = [];\n\t\tthis._enterGuards.clear();\n\t\tthis._leaveGuards.clear();\n\t}\n\n\t/**\n\t * Run the full guard pipeline (leave -> global enter -> route enter) and\n\t * return a normalized decision. Stays synchronous when all guards return\n\t * plain values; returns a Promise only when an async guard is encountered.\n\t *\n\t * @param context - Complete guard context including AbortSignal.\n\t * `context.fromRoute` controls leave-guard lookup: empty string skips leave guards.\n\t * @param options - Optional evaluation options.\n\t * @param options.skipLeaveGuards - When true, leave guards are skipped even if\n\t * `context.fromRoute` is set. Used by redirect chain hops to avoid re-running\n\t * leave guards while still preserving `fromRoute` in the context.\n\t * @returns A synchronous {@link GuardDecision} when all guards return plain values,\n\t * or a `Promise<GuardDecision>` when at least one guard returns a thenable.\n\t */\n\tevaluate(context: GuardContext, options?: { skipLeaveGuards?: boolean }): GuardDecision | Promise<GuardDecision> {\n\t\tconst hasLeaveGuards =\n\t\t\t!options?.skipLeaveGuards && context.fromRoute !== \"\" && this._leaveGuards.has(context.fromRoute);\n\t\tconst hasEnterGuards =\n\t\t\tthis._globalGuards.length > 0 || (context.toRoute !== \"\" && this._enterGuards.has(context.toRoute));\n\n\t\tif (!hasLeaveGuards && !hasEnterGuards) {\n\t\t\treturn { action: \"allow\" };\n\t\t}\n\n\t\tconst processEnterResult = (\n\t\t\tenterResult: GuardResult | Promise<GuardResult>,\n\t\t): GuardDecision | Promise<GuardDecision> => {\n\t\t\tif (isPromiseLike(enterResult)) {\n\t\t\t\treturn enterResult\n\t\t\t\t\t.then((r: GuardResult): GuardDecision => {\n\t\t\t\t\t\tif (r === true) return { action: \"allow\" };\n\t\t\t\t\t\tif (r === false) return { action: \"block\" };\n\t\t\t\t\t\treturn { action: \"redirect\", target: r };\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error: unknown): GuardDecision => {\n\t\t\t\t\t\treturn { action: \"error\", error };\n\t\t\t\t\t});\n\t\t\t}\n\t\t\tif (enterResult === true) return { action: \"allow\" };\n\t\t\tif (enterResult === false) return { action: \"block\" };\n\t\t\treturn { action: \"redirect\", target: enterResult };\n\t\t};\n\n\t\tconst runEnterPhase = (): GuardDecision | Promise<GuardDecision> => {\n\t\t\tconst enterResult = this._runEnterGuards(context.toRoute, context);\n\t\t\treturn processEnterResult(enterResult);\n\t\t};\n\n\t\ttry {\n\t\t\tif (hasLeaveGuards) {\n\t\t\t\tconst leaveResult = this._runLeaveGuards(context);\n\n\t\t\t\tif (isPromiseLike(leaveResult)) {\n\t\t\t\t\treturn leaveResult\n\t\t\t\t\t\t.then((allowed: boolean): GuardDecision | Promise<GuardDecision> => {\n\t\t\t\t\t\t\tif (allowed !== true) return { action: \"block\" };\n\t\t\t\t\t\t\tif (context.signal.aborted) return { action: \"block\" };\n\t\t\t\t\t\t\treturn runEnterPhase();\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch((error: unknown): GuardDecision => {\n\t\t\t\t\t\t\treturn { action: \"error\", error };\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (leaveResult !== true) return { action: \"block\" };\n\t\t\t}\n\n\t\t\treturn runEnterPhase();\n\t\t} catch (error) {\n\t\t\treturn { action: \"error\", error };\n\t\t}\n\t}\n\n\tprivate _addToGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\t\tlet guards = map.get(key);\n\t\tif (!guards) {\n\t\t\tguards = [];\n\t\t\tmap.set(key, guards);\n\t\t}\n\t\tguards.push(guard);\n\t}\n\n\tprivate _removeFromGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\t\tconst guards = map.get(key);\n\t\tif (!guards) return;\n\t\tconst index = guards.indexOf(guard);\n\t\tif (index !== -1) guards.splice(index, 1);\n\t\tif (guards.length === 0) map.delete(key);\n\t}\n\n\t/**\n\t * Run leave guards for the current route. Returns boolean (no redirects).\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runLeaveGuards(context: GuardContext): boolean | Promise<boolean> {\n\t\tconst registered = this._leaveGuards.get(context.fromRoute);\n\t\tif (!registered || registered.length === 0) return true;\n\n\t\tconst guards = registered.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateLeaveGuardResult(candidate),\n\t\t\t\t\t\t\"Leave guard\",\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t) as Promise<boolean>;\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateLeaveGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Leave guard [${i}] on route \"${context.fromRoute}\" threw, navigation failed`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** Run global guards, then route-specific guards. Stays sync when possible. */\n\tprivate _runEnterGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tconst globalResult = this._runGuards(this._globalGuards, context);\n\n\t\tif (isPromiseLike(globalResult)) {\n\t\t\treturn globalResult.then((result: GuardResult) => {\n\t\t\t\tif (result !== true) return result;\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\treturn this._runRouteGuards(toRoute, context);\n\t\t\t});\n\t\t}\n\t\tif (globalResult !== true) return globalResult;\n\t\treturn this._runRouteGuards(toRoute, context);\n\t}\n\n\t/** Run route-specific guards if any are registered. */\n\tprivate _runRouteGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tif (!toRoute || !this._enterGuards.has(toRoute)) return true;\n\t\treturn this._runGuards(this._enterGuards.get(toRoute)!, context);\n\t}\n\n\t/**\n\t * Run guards sync; switch to async path if a Promise is returned.\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runGuards(guards: GuardFn[], context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tguards = guards.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateGuardResult(candidate),\n\t\t\t\t\t\t\"Enter guard\",\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Enter guard [${i}] on route \"${context.toRoute}\" threw, navigation failed`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Continue guard array async from the first Promise onward.\n\t *\n\t * Shared by both enter and leave guard pipelines. The `onBlock` callback\n\t * determines what to return for non-true results: leave guards always\n\t * return `false`, enter guards validate and may return redirects.\n\t *\n\t * @param isLeaveGuard - When true, error logs reference `fromRoute`; otherwise `toRoute`.\n\t */\n\tprivate async _continueGuardsAsync(\n\t\tpendingResult: PromiseLike<GuardResult>,\n\t\tguards: GuardFn[],\n\t\tcurrentIndex: number,\n\t\tcontext: GuardContext,\n\t\tonBlock: (result: unknown) => GuardResult,\n\t\tlabel: string,\n\t\tisLeaveGuard: boolean,\n\t): Promise<GuardResult> {\n\t\tlet guardIndex = currentIndex;\n\t\ttry {\n\t\t\tconst result = await pendingResult;\n\t\t\tif (result !== true) return onBlock(result);\n\n\t\t\tfor (let i = currentIndex + 1; i < guards.length; i++) {\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tguardIndex = i;\n\t\t\t\tconst nextResult = await guards[i](context);\n\t\t\t\tif (nextResult !== true) return onBlock(nextResult);\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (!context.signal.aborted) {\n\t\t\t\tconst route = isLeaveGuard ? context.fromRoute : context.toRoute;\n\t\t\t\tLog.error(\n\t\t\t\t\t`${label} [${guardIndex}] on route \"${route}\" threw, navigation failed`,\n\t\t\t\t\tString(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/** Validate a non-true guard result; invalid values become false. */\n\tprivate _validateGuardResult(result: unknown): GuardResult {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tif (typeof result === \"string\" && result.length > 0) return result;\n\t\tif (isGuardRedirect(result)) return result;\n\t\tLog.warning(\"Guard returned invalid value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n\n\t/** Validate a leave guard result; non-boolean values log a warning and block. */\n\tprivate _validateLeaveGuardResult(result: unknown): boolean {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tLog.warning(\"Leave guard returned non-boolean value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n}\n"],"mappings":"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","ignoreList":[],"sourceRoot":""}},{"offset":{"line":2,"column":0},"map":{"version":3,"names":["NavigationOutcome","Object","freeze","Committed","Bypassed","Blocked","Redirected","Cancelled","Error"],"sources":["NavigationOutcome.ts"],"sourcesContent":["/**\n * Outcome of a navigation after the guard pipeline settles.\n *\n * Registered as a UI5 enum via `library.ts` so that it is discoverable\n * through `sap.ui.base.DataType.getType()`. Application code can import\n * the value object directly.\n *\n * @enum {string}\n * @namespace ui5.guard.router\n * @since 1.2.0\n */\nconst NavigationOutcome = Object.freeze({\n\t/** Navigation was allowed and the target route activated. @since 1.2.0 */\n\tCommitted: \"committed\",\n\t/** Navigation was allowed, but no route matched; UI5 continued with bypassed handling. @since 1.3.0 */\n\tBypassed: \"bypassed\",\n\t/** A guard blocked navigation; the previous route remains active. @since 1.2.0 */\n\tBlocked: \"blocked\",\n\t/** A guard redirected navigation to a different route. @since 1.2.0 */\n\tRedirected: \"redirected\",\n\t/** Navigation was cancelled before settling (superseded, stopped, or destroyed). @since 1.2.0 */\n\tCancelled: \"cancelled\",\n\t/** A guard threw or rejected; the previous route remains active. @since 1.4.0 */\n\tError: \"error\",\n});\n\ntype NavigationOutcome = (typeof NavigationOutcome)[keyof typeof NavigationOutcome];\n\nexport default NavigationOutcome;\n"],"mappings":"AAAA,kFAWA,MAAMA,EAAoBC,OAAOC,OAAO,CAEvCC,UAAW,YAEXC,SAAU,WAEVC,QAAS,UAETC,WAAY,aAEZC,UAAW,YAEXC,MAAO,UACL,OAIYR,CAAiB","ignoreList":[],"sourceRoot":""}},{"offset":{"line":3,"column":0},"map":{"version":3,"names":["NavigationOutcome","_interopRequireDefault","__NavigationOutcome","GuardPipeline","__GuardPipeline","isPromiseLike","HistoryDirection","coreLibrary","routing","LOG_COMPONENT","isRouteGuardConfig","guard","IDLE","kind","isRecord","value","Array","isArray","proto","Object","getPrototypeOf","prototype","isOneOf","values","set","Set","v","has","isUnknownRouteRegistrationPolicy","isNavToPreflightMode","isGuardLoading","isInheritance","OPTIONAL_OR_REST_SEGMENT","stripInlineQuery","seg","mqIdx","indexOf","slice","oqIdx","patternSegments","pattern","split","map","filter","test","isPatternAncestor","ancestorPattern","candidatePattern","ancestorSegments","length","candidateSegments","every","i","candidateSeg","startsWith","resolveGuardModulePath","dotPath","componentNamespace","replace","fullDotPath","parseGuardEntry","entry","hashIndex","rawPath","exportKey","undefined","modulePath","lastSegment","pop","name","guardWarning","detail","Log","warning","resolveModuleExports","moduleExport","descriptorName","moduleName","debug","fn","index","parseInt","Number","isNaN","results","push","entries","resolvedName","key","val","parseGuardDescriptors","guards","JSON","stringify","descriptors","pushEntries","route","type","label","parsed","config","leave","enter","info","DEFAULT_OPTIONS","unknownRouteRegistration","navToPreflight","guardLoading","inheritance","applyOption","raw","target","normalizeGuardRouterOptions","result","MAX_REDIRECT_DEPTH","Router","MobileRouter","extend","constructor","_constructor","args","routes","owner","rest","rawConfig","isRecordConfig","guardRouter","cleanConfig","MobileRouter.prototype.constructor.apply","this","_options","_pipeline","_currentRoute","_currentHash","_phase","_parseGeneration","_suppressedHash","_settlementResolvers","_lastSettlement","_pendingGuardDescriptors","_sourceDescriptors","_destroyed","_manifestMeta","Map","_runtimeMeta","_resolvedMetaCache","_routeNames","r","keys","routeMeta","routeName","meta","freeze","appConfig","getManifestEntry","id","uniquePaths","d","sap","ui","require","initialize","_initialize","MobileRouter.prototype.initialize.call","expandedDescriptors","_expandGuardDescriptors","_registerLazyGuards","_loadAndRegisterGuards","then","catch","err","error","String","addRoute","_addRoute","oConfig","MobileRouter.prototype.addRoute.apply","includes","clear","getRoute","newPattern","getPattern","newDescriptors","_expandGuardDescriptorsForNewRoute","newName","descriptor","ancestorRoute","_collectRoutePatterns","toSorted","a","b","pa","pb","addGuard","_addGuard","_isFn","addGlobalGuard","removeGuard","_removeGuard","removeGlobalGuard","addRouteGuard","_addRouteGuard","_handleUnknownRouteRegistration","hasHandler","beforeEnter","addEnterGuard","beforeLeave","addLeaveGuard","removeRouteGuard","_removeRouteGuard","removeLeaveGuard","removeEnterGuard","_addLeaveGuard","_resolveNavToArgs","componentTargetInfoOrReplace","replaceOrOptions","options","guardOptions","componentTargetInfo","method","methodName","Error","_removeLeaveGuard","getRouteMeta","_getRouteMeta","_EMPTY_META","cached","get","_resolveInheritedMeta","_resolveFlatMeta","setRouteMeta","_setRouteMeta","navigationSettled","_navigationSettled","Promise","resolve","status","Committed","hash","attachNavigationSettled","_attachNavigationSettled","oData","fnFunction","oListener","attachEvent","detachNavigationSettled","_detachNavigationSettled","detachEvent","_flushSettlement","resolvers","fireEvent","navTo","_navTo","parameters","origin","MobileRouter.prototype.navTo.call","_cancelPendingNavigation","targetHash","getURL","routeInfo","getRouteInfoByHash","toRoute","attempt","skipGuards","_commitNavigation","controller","AbortController","generation","context","_createGuardContext","signal","decision","evaluate","_applyPreflightDecision","bag","_errorNavigation","bReplace","action","_blockNavigation","_startRedirectChain","parse","_parse","newHash","_applyDecision","stop","_stop","MobileRouter.prototype.stop.call","abort","Cancelled","wasRedirect","Redirected","Bypassed","MobileRouter.prototype.parse.call","_redirect","chain","targetName","targetParameters","targetRoute","visited","join","attemptedHash","restoreHash","size","add","settlementBefore","resolvedHash","toHash","toArguments","arguments","fromRoute","fromHash","toMeta","fromMeta","skipLeaveGuards","_applyRedirectDecision","redirectsToCurrentHash","Blocked","_restoreHashIfNeeded","_restoreHash","suppressParse","hashChanger","getHashChanger","replaceHash","Unknown","allRoutes","patternByName","expanded","sort","manifest","runtime","routeEntry","find","ancestors","merged","ancestor","ancestorManifest","assign","ancestorRuntime","ownManifest","ownRuntime","promises","all","exports","_registerGuardFromDescriptor","guardFn","lazyGuard","reject","mod","exp","lazyExpander","destroy","_destroy","MobileRouter.prototype.destroy.call"],"sources":["Router.ts"],"sourcesContent":["import MobileRouter from \"sap/m/routing/Router\";\nimport Log from \"sap/base/Log\";\nimport coreLibrary from \"sap/ui/core/library\";\nimport type { ComponentTargetParameters } from \"sap/ui/core/routing/Router\";\nimport type { $RouteSettings } from \"sap/ui/core/routing/Route\";\nimport type {\n\tGuardFn,\n\tGuardContext,\n\tGuardNavToOptions,\n\tGuardResult,\n\tGuardRedirect,\n\tGuardRouter,\n\tGuardLoading,\n\tInheritance,\n\tLeaveGuardFn,\n\tManifestRouteGuardConfig,\n\tNavToPreflightMode,\n\tNavigationResult,\n\tRouter$NavigationSettledEvent,\n\tRouteGuardConfig,\n\tUnknownRouteRegistrationPolicy,\n} from \"./types\";\nimport NavigationOutcome from \"./NavigationOutcome\";\nimport GuardPipeline, { type GuardDecision, isPromiseLike } from \"./GuardPipeline\";\n\nconst HistoryDirection = coreLibrary.routing.HistoryDirection;\n\nconst LOG_COMPONENT = \"ui5.guard.router.Router\";\n\nfunction isRouteGuardConfig(guard: GuardFn | RouteGuardConfig): guard is RouteGuardConfig {\n\treturn typeof guard === \"object\" && guard !== null;\n}\n\n/** Snapshot of an in-flight navigation being evaluated by the guard pipeline. */\ninterface NavigationAttempt {\n\treadonly hash: string;\n\treadonly route: string;\n\treadonly controller: AbortController;\n\treadonly generation: number;\n}\n\ninterface PhaseIdle {\n\treadonly kind: \"idle\";\n}\n\ninterface PhaseEvaluating {\n\treadonly kind: \"evaluating\";\n\treadonly attempt: NavigationAttempt;\n}\n\ninterface PhaseCommitting {\n\treadonly kind: \"committing\";\n\treadonly hash: string;\n\treadonly route: string;\n\treadonly origin: \"preflight\" | \"redirect\" | \"parse\";\n}\n\ntype RouterPhase = PhaseIdle | PhaseEvaluating | PhaseCommitting;\n\nconst IDLE: PhaseIdle = { kind: \"idle\" };\n\n/** Type guard for plain objects. */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n\tconst proto = Object.getPrototypeOf(value);\n\treturn proto === Object.prototype || proto === null;\n}\n\n/** Create a type-narrowing validator for a finite set of string literal values. */\nfunction isOneOf<T extends string>(...values: T[]): (v: unknown) => v is T {\n\tconst set: ReadonlySet<string> = new Set(values);\n\treturn (v: unknown): v is T => typeof v === \"string\" && set.has(v);\n}\n\nconst isUnknownRouteRegistrationPolicy = isOneOf<UnknownRouteRegistrationPolicy>(\"ignore\", \"warn\", \"throw\");\nconst isNavToPreflightMode = isOneOf<NavToPreflightMode>(\"guard\", \"bypass\", \"off\");\nconst isGuardLoading = isOneOf<GuardLoading>(\"block\", \"lazy\");\nconst isInheritance = isOneOf<Inheritance>(\"none\", \"pattern-tree\");\n\n/** Matches a standalone optional (`:param:`) or rest (`:param*:`) segment. */\nconst OPTIONAL_OR_REST_SEGMENT = /^:[^:]*\\*?:$/;\n\n/**\n * Strips inline query and optional-query suffixes from a segment.\n *\n * UI5 (crossroads.js) allows query parameters to attach directly to a\n * path segment without a `/` separator:\n * - `product{?query}` → mandatory query on `product`\n * - `product:?query:` → optional query on `product`\n * - `{id}{?query}` → mandatory param + mandatory query\n *\n * For pattern-tree ancestry we only care about the path portion,\n * so these suffixes are stripped.\n */\nfunction stripInlineQuery(seg: string): string {\n\t// Strip mandatory query `{?...}` suffix\n\tconst mqIdx = seg.indexOf(\"{?\");\n\tif (mqIdx !== -1) return seg.slice(0, mqIdx);\n\t// Strip optional query `:?...:` suffix\n\tconst oqIdx = seg.indexOf(\":?\");\n\tif (oqIdx !== -1) return seg.slice(0, oqIdx);\n\treturn seg;\n}\n\n/**\n * Extract mandatory path segments from a UI5 route pattern.\n *\n * Splits on `/`, strips inline query suffixes, then drops empty segments,\n * standalone optional (`:param:`), and rest (`:param*:`) segments.\n */\nfunction patternSegments(pattern: string): string[] {\n\treturn pattern\n\t\t.split(\"/\")\n\t\t.map(stripInlineQuery)\n\t\t.filter((seg) => seg !== \"\" && !OPTIONAL_OR_REST_SEGMENT.test(seg));\n}\n\n/**\n * Check if `ancestorPattern` is a URL-tree ancestor of `candidatePattern`.\n *\n * Both patterns are reduced to their mandatory path segments and compared\n * positionally. Mandatory parameter segments (`{paramA}`, `{paramB}`) are\n * treated as equivalent regardless of name, so `employees/{empId}` is\n * recognized as an ancestor of `employees/{id}/resume`.\n */\nfunction isPatternAncestor(ancestorPattern: string, candidatePattern: string): boolean {\n\tif (ancestorPattern === \"\") return true;\n\tconst ancestorSegments = patternSegments(ancestorPattern);\n\tif (ancestorSegments.length === 0) return false;\n\tconst candidateSegments = patternSegments(candidatePattern);\n\tif (candidateSegments.length <= ancestorSegments.length) return false;\n\treturn ancestorSegments.every((seg, i) => {\n\t\tconst candidateSeg = candidateSegments[i];\n\t\tif (seg === candidateSeg) return true;\n\t\t// Treat any two mandatory parameter segments as equivalent\n\t\treturn seg.startsWith(\"{\") && candidateSeg.startsWith(\"{\");\n\t});\n}\n\n/** Parsed guard declaration from the manifest `guards` block. */\ninterface GuardDescriptor {\n\treadonly route: string; // \"*\" for global, route name for per-route\n\treadonly type: \"enter\" | \"leave\";\n\treadonly modulePath: string;\n\treadonly name: string;\n\treadonly exportKey?: string;\n}\n\n/**\n * Resolve a dot-notation module path following UI5 routing conventions.\n * Mirrors `sap.ui.core.routing.Target._getEffectiveObjectName()`.\n *\n * - Paths prefixed with `\"module:\"` are treated as absolute (the prefix is\n * stripped and dots become slashes).\n * - All other paths are prefixed with the component namespace.\n */\nfunction resolveGuardModulePath(dotPath: string, componentNamespace: string): string {\n\tif (dotPath.startsWith(\"module:\")) {\n\t\treturn dotPath.slice(\"module:\".length).replace(/\\./g, \"/\");\n\t}\n\tconst fullDotPath = componentNamespace ? componentNamespace + \".\" + dotPath : dotPath;\n\treturn fullDotPath.replace(/\\./g, \"/\");\n}\n\n/**\n * Split a manifest guard entry on the first `#` to separate the module path\n * from an optional export key, then derive a human-readable guard name.\n */\nfunction parseGuardEntry(\n\tentry: string,\n\tcomponentNamespace: string,\n): { modulePath: string; name: string; exportKey?: string } {\n\tconst hashIndex = entry.indexOf(\"#\");\n\tconst rawPath = hashIndex === -1 ? entry : entry.slice(0, hashIndex);\n\tconst exportKey = hashIndex === -1 ? undefined : entry.slice(hashIndex + 1);\n\n\tconst modulePath = resolveGuardModulePath(rawPath, componentNamespace);\n\n\t// Name: export key if present, otherwise last segment of the dot path\n\tconst lastSegment = rawPath.split(\".\").pop() ?? rawPath;\n\tconst name = exportKey ?? lastSegment;\n\n\treturn { modulePath, name, exportKey };\n}\n\ninterface ResolvedGuardExport {\n\treadonly name: string;\n\treadonly fn: GuardFn;\n}\n\n/** Log a warning about a guard module entry in the manifest. */\nfunction guardWarning(modulePath: string, detail: string): void {\n\tLog.warning(`guardRouter.guards: \"${modulePath}\" ${detail}`, undefined, LOG_COMPONENT);\n}\n\n/**\n * Detect the export shape of a loaded guard module and extract guard functions.\n *\n * Shapes:\n * - function → single guard\n * - Array → ordered guards (non-functions warned and skipped)\n * - plain object → named guards in key order (non-functions warned and skipped)\n *\n * When `exportKey` is set, only the matching export is returned.\n * When `exportKey` is set on a function export, the key is ignored with a debug warning.\n */\nfunction resolveModuleExports(\n\tmoduleExport: unknown,\n\tmodulePath: string,\n\tdescriptorName: string,\n\texportKey?: string,\n): ResolvedGuardExport[] {\n\tconst moduleName = modulePath.split(\"/\").pop() ?? modulePath;\n\n\t// Shape 1: function\n\tif (typeof moduleExport === \"function\") {\n\t\tif (exportKey !== undefined) {\n\t\t\tLog.debug(\n\t\t\t\t`guardRouter.guards: \"${modulePath}#${exportKey}\" is a single function, ignoring export key`,\n\t\t\t\tundefined,\n\t\t\t\tLOG_COMPONENT,\n\t\t\t);\n\t\t}\n\t\treturn [{ name: descriptorName, fn: moduleExport as GuardFn }];\n\t}\n\n\t// Shape 2: array\n\tif (Array.isArray(moduleExport)) {\n\t\tif (moduleExport.length === 0) {\n\t\t\tguardWarning(modulePath, \"exported an empty array, skipping\");\n\t\t\treturn [];\n\t\t}\n\n\t\tif (exportKey !== undefined) {\n\t\t\tconst index = parseInt(exportKey, 10);\n\t\t\tif (Number.isNaN(index) || index < 0 || index >= moduleExport.length) {\n\t\t\t\tguardWarning(modulePath, `#${exportKey} - index out of range, skipping`);\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tconst entry = moduleExport[index] as unknown;\n\t\t\tif (typeof entry !== \"function\") {\n\t\t\t\tguardWarning(modulePath, `#${exportKey} is not a function, skipping`);\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\treturn [{ name: `${moduleName}#${exportKey}`, fn: entry as GuardFn }];\n\t\t}\n\n\t\tconst results: ResolvedGuardExport[] = [];\n\t\tfor (let i = 0; i < moduleExport.length; i++) {\n\t\t\tconst entry = moduleExport[i] as unknown;\n\t\t\tif (typeof entry !== \"function\") {\n\t\t\t\tguardWarning(modulePath, `[${i}] is not a function, skipping`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresults.push({ name: `${moduleName}#${i}`, fn: entry as GuardFn });\n\t\t}\n\t\treturn results;\n\t}\n\n\t// Shape 3: plain object\n\tif (isRecord(moduleExport)) {\n\t\tconst entries = Object.entries(moduleExport);\n\t\tif (entries.length === 0) {\n\t\t\tguardWarning(modulePath, \"exported an empty object, skipping\");\n\t\t\treturn [];\n\t\t}\n\n\t\tif (exportKey !== undefined) {\n\t\t\tlet value: unknown = moduleExport[exportKey];\n\t\t\tlet resolvedName = exportKey;\n\t\t\tif (value === undefined) {\n\t\t\t\tconst index = parseInt(exportKey, 10);\n\t\t\t\tif (!Number.isNaN(index) && index >= 0 && index < entries.length) {\n\t\t\t\t\tconst [key, val] = entries[index];\n\t\t\t\t\tvalue = val;\n\t\t\t\t\tresolvedName = key;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (value === undefined) {\n\t\t\t\tguardWarning(modulePath, `#${exportKey} - key not found, skipping`);\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tif (typeof value !== \"function\") {\n\t\t\t\tguardWarning(modulePath, `#${exportKey} is not a function, skipping`);\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\treturn [{ name: resolvedName, fn: value as GuardFn }];\n\t\t}\n\n\t\tconst results: ResolvedGuardExport[] = [];\n\t\tfor (const [key, value] of entries) {\n\t\t\tif (typeof value !== \"function\") {\n\t\t\t\tguardWarning(modulePath, `.${key} is not a function, skipping`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresults.push({ name: key, fn: value as GuardFn });\n\t\t}\n\t\treturn results;\n\t}\n\n\tguardWarning(modulePath, \"did not export a function, array, or plain object, skipping\");\n\treturn [];\n}\n\n/**\n * Parse the `guards` block from the guardRouter config into an array of\n * {@link GuardDescriptor} objects.\n *\n * Handles:\n * - `\"*\"` key with `string[]` -> global enter guards\n * - Route name with `string[]` (shorthand) -> enter guards\n * - Route name with `{ enter: [...], leave: [...] }` -> enter + leave guards\n * - `\"*\"` with object form -> warn, treat enter as global\n * - `\"*\"` leave -> warn, skip (global leave guards not supported)\n * - Invalid entries -> warn, skip\n */\nfunction parseGuardDescriptors(guards: unknown, componentNamespace: string): GuardDescriptor[] {\n\tif (!isRecord(guards)) {\n\t\tLog.warning(\"guardRouter.guards is not a plain object, skipping\", JSON.stringify(guards), LOG_COMPONENT);\n\t\treturn [];\n\t}\n\n\tconst descriptors: GuardDescriptor[] = [];\n\n\tfunction pushEntries(entries: unknown[], route: string, type: \"enter\" | \"leave\", label: string): void {\n\t\tfor (const entry of entries) {\n\t\t\tif (typeof entry !== \"string\" || entry.length === 0) {\n\t\t\t\tLog.warning(\n\t\t\t\t\t`guardRouter.guards${label}: invalid entry, skipping`,\n\t\t\t\t\tJSON.stringify(entry),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst parsed = parseGuardEntry(entry, componentNamespace);\n\t\t\tdescriptors.push({ route, type, ...parsed });\n\t\t}\n\t}\n\n\tfor (const [key, value] of Object.entries(guards)) {\n\t\tif (Array.isArray(value)) {\n\t\t\tpushEntries(value, key, \"enter\", `[\"${key}\"]`);\n\t\t} else if (isRecord(value)) {\n\t\t\tconst config = value as ManifestRouteGuardConfig;\n\n\t\t\tif (key === \"*\" && config.leave !== undefined) {\n\t\t\t\tLog.warning(\n\t\t\t\t\t'guardRouter.guards[\"*\"].leave: global leave guards are not supported, skipping',\n\t\t\t\t\tundefined,\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (key === \"*\" && config.enter === undefined && config.leave !== undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (key === \"*\" && config.enter !== undefined) {\n\t\t\t\tLog.info('guardRouter.guards[\"*\"]: object form; treating enter as global', undefined, LOG_COMPONENT);\n\t\t\t}\n\n\t\t\tif (Array.isArray(config.enter)) {\n\t\t\t\tpushEntries(config.enter, key, \"enter\", `[\"${key}\"].enter`);\n\t\t\t}\n\n\t\t\tif (key !== \"*\" && Array.isArray(config.leave)) {\n\t\t\t\tpushEntries(config.leave, key, \"leave\", `[\"${key}\"].leave`);\n\t\t\t}\n\t\t} else {\n\t\t\tLog.warning(\n\t\t\t\t`guardRouter.guards[\"${key}\"]: expected string[] or { enter?, leave? }, skipping`,\n\t\t\t\tJSON.stringify(value),\n\t\t\t\tLOG_COMPONENT,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn descriptors;\n}\n\ninterface ResolvedGuardRouterOptions {\n\treadonly unknownRouteRegistration: UnknownRouteRegistrationPolicy;\n\treadonly navToPreflight: NavToPreflightMode;\n\treadonly guardLoading: GuardLoading;\n\treadonly inheritance: Inheritance;\n}\n\nconst DEFAULT_OPTIONS: ResolvedGuardRouterOptions = {\n\tunknownRouteRegistration: \"warn\",\n\tnavToPreflight: \"guard\",\n\tguardLoading: \"lazy\",\n\tinheritance: \"none\",\n};\n\nfunction applyOption<K extends keyof ResolvedGuardRouterOptions>(\n\traw: Record<string, unknown>,\n\tkey: K,\n\tguard: (v: unknown) => v is ResolvedGuardRouterOptions[K],\n\ttarget: { -readonly [P in keyof ResolvedGuardRouterOptions]: ResolvedGuardRouterOptions[P] },\n): void {\n\tif (raw[key] !== undefined) {\n\t\tif (guard(raw[key])) {\n\t\t\ttarget[key] = raw[key] as ResolvedGuardRouterOptions[K];\n\t\t} else {\n\t\t\tLog.warning(`guardRouter.${key} has invalid value, using default`, JSON.stringify(raw[key]), LOG_COMPONENT);\n\t\t}\n\t}\n}\n\nfunction normalizeGuardRouterOptions(raw: unknown): ResolvedGuardRouterOptions {\n\tif (!isRecord(raw)) {\n\t\tif (raw !== undefined) {\n\t\t\tLog.warning(\"guardRouter config is not a plain object, using defaults\", JSON.stringify(raw), LOG_COMPONENT);\n\t\t}\n\t\treturn DEFAULT_OPTIONS;\n\t}\n\n\tconst result = { ...DEFAULT_OPTIONS };\n\tapplyOption(raw, \"unknownRouteRegistration\", isUnknownRouteRegistrationPolicy, result);\n\tapplyOption(raw, \"navToPreflight\", isNavToPreflightMode, result);\n\tapplyOption(raw, \"guardLoading\", isGuardLoading, result);\n\tapplyOption(raw, \"inheritance\", isInheritance, result);\n\treturn result;\n}\n\n/** Maximum number of hops in a redirect chain before it is treated as a loop. */\nconst MAX_REDIRECT_DEPTH = 10;\n\n/** State threaded through a redirect chain. */\ninterface RedirectChainContext {\n\t/** Hashes whose guards have been evaluated in this chain (mutated via .add()). */\n\tvisited: Set<string>;\n\t/** Hash of the originally attempted navigation (for settlement / hash restore). */\n\treadonly attemptedHash: string | undefined;\n\t/** Whether to restore the hash on block (true for parse path, false for preflight). */\n\treadonly restoreHash: boolean;\n\t/** Original source route (the route the user occupies). */\n\treadonly fromRoute: string;\n\t/** Original source hash (the hash the user occupies). */\n\treadonly fromHash: string;\n\t/** Shared AbortSignal from the original navigation. */\n\treadonly signal: AbortSignal;\n\t/** Shared generation counter from the original navigation. */\n\treadonly generation: number;\n\t/** Shared bag from the original navigation's guard context. */\n\treadonly bag: Map<string, unknown>;\n}\n\n/**\n * Router with navigation guard support.\n *\n * Extends `sap.m.routing.Router` with a shared guard pipeline that\n * evaluates registered guard functions before route matching, target\n * loading, or event firing occurs.\n *\n * Two entry points feed the same pipeline:\n * - `navTo()` runs guards as a preflight check. Blocked or redirected\n * navigations never change the hash or push history entries.\n * - `parse()` runs guards as a fallback for browser back/forward, URL\n * bar entry, and direct hash changes where the hash has already changed\n * before guards can intercept.\n *\n * Key assumptions (see docs/reference/architecture.md for full rationale):\n * - `parse()` is intentionally NOT async. Sync guards execute in the\n * same tick; async guards fall back to a deferred path.\n * - `replaceHash` fires `hashChanged` synchronously (validated by test).\n * - `setHash` (via `super.navTo`) fires `hashChanged` synchronously (validated by test).\n * - Redirect targets are evaluated by the guard pipeline with loop detection.\n *\n * @namespace ui5.guard.router\n * @extends sap.m.routing.Router\n */\nexport default class Router extends MobileRouter implements GuardRouter {\n\tprivate _options: ResolvedGuardRouterOptions = DEFAULT_OPTIONS;\n\tprivate _pipeline = new GuardPipeline();\n\tprivate _currentRoute = \"\";\n\tprivate _currentHash: string | null = null;\n\tprivate _phase: RouterPhase = IDLE;\n\tprivate _parseGeneration = 0;\n\tprivate _suppressedHash: string | null = null;\n\tprivate _settlementResolvers: ((result: NavigationResult) => void)[] = [];\n\tprivate _lastSettlement: NavigationResult | null = null;\n\tprivate _pendingGuardDescriptors: GuardDescriptor[] = [];\n\tprivate _sourceDescriptors: GuardDescriptor[] = [];\n\tprivate _destroyed = false;\n\tprivate _manifestMeta = new Map<string, Readonly<Record<string, unknown>>>();\n\tprivate _runtimeMeta = new Map<string, Readonly<Record<string, unknown>>>();\n\tprivate _resolvedMetaCache = new Map<string, Readonly<Record<string, unknown>>>();\n\tprivate _routeNames: string[] = [];\n\n\tconstructor(...args: ConstructorParameters<typeof MobileRouter>) {\n\t\tconst [routes, config, owner, ...rest] = args;\n\t\tconst rawConfig = config as Record<string, unknown> | undefined;\n\t\tconst isRecordConfig = isRecord(rawConfig);\n\t\tconst { guardRouter, ...cleanConfig } = isRecordConfig ? rawConfig : ({} as Record<string, unknown>);\n\t\tsuper(routes, isRecordConfig ? (cleanConfig as typeof config) : config, owner, ...rest);\n\t\tthis._options = normalizeGuardRouterOptions(guardRouter);\n\n\t\t// Collect route names from the constructor's routes parameter for pattern-tree traversal.\n\t\tif (Array.isArray(routes)) {\n\t\t\tthis._routeNames = routes\n\t\t\t\t.filter((r): r is { name: string } => isRecord(r) && typeof r.name === \"string\")\n\t\t\t\t.map((r) => r.name);\n\t\t} else if (isRecord(routes)) {\n\t\t\tthis._routeNames = Object.keys(routes);\n\t\t}\n\n\t\tif (isRecord(guardRouter) && guardRouter.routeMeta !== undefined) {\n\t\t\tif (isRecord(guardRouter.routeMeta)) {\n\t\t\t\tfor (const [routeName, meta] of Object.entries(guardRouter.routeMeta)) {\n\t\t\t\t\tif (isRecord(meta)) {\n\t\t\t\t\t\tthis._manifestMeta.set(routeName, Object.freeze({ ...meta }));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tLog.warning(\n\t\t\t\t\t\t\t`guardRouter.routeMeta[\"${routeName}\"]: expected object, skipping`,\n\t\t\t\t\t\t\tJSON.stringify(meta),\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tLog.warning(\n\t\t\t\t\t\"guardRouter.routeMeta: expected object, skipping\",\n\t\t\t\t\tJSON.stringify(guardRouter.routeMeta),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (isRecord(guardRouter) && guardRouter.guards !== undefined) {\n\t\t\tlet componentNamespace = \"\";\n\t\t\tif (owner) {\n\t\t\t\tconst appConfig = owner.getManifestEntry(\"sap.app\") as Record<string, unknown> | undefined;\n\t\t\t\tif (isRecord(appConfig) && typeof appConfig.id === \"string\") {\n\t\t\t\t\tcomponentNamespace = appConfig.id;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._pendingGuardDescriptors = parseGuardDescriptors(guardRouter.guards, componentNamespace);\n\n\t\t\t// Fire-and-forget preload hint: warm the module cache so lazy\n\t\t\t// wrappers resolve synchronously on first navigation.\n\t\t\t// Block mode loads modules itself in initialize().\n\t\t\tif (this._pendingGuardDescriptors.length > 0 && this._options.guardLoading === \"lazy\") {\n\t\t\t\tconst uniquePaths = [...new Set(this._pendingGuardDescriptors.map((d) => d.modulePath))];\n\t\t\t\tsap.ui.require(uniquePaths);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Initialize the router. When manifest guards are declared and\n\t * `guardLoading` is `\"block\"`, module loading starts and\n\t * `super.initialize()` is deferred until all modules are loaded.\n\t * In `\"lazy\"` mode, lazy wrappers are registered synchronously\n\t * and `super.initialize()` is called immediately.\n\t *\n\t * @override sap.ui.core.routing.Router#initialize\n\t * @since 1.0.1\n\t */\n\toverride initialize(): this {\n\t\tif (this._pendingGuardDescriptors.length === 0) {\n\t\t\treturn super.initialize();\n\t\t}\n\n\t\tconst descriptors = this._pendingGuardDescriptors;\n\t\tthis._pendingGuardDescriptors = [];\n\t\tthis._sourceDescriptors = descriptors;\n\n\t\tconst expandedDescriptors =\n\t\t\tthis._options.inheritance === \"pattern-tree\" ? this._expandGuardDescriptors(descriptors) : descriptors;\n\n\t\tif (this._options.guardLoading === \"lazy\") {\n\t\t\tthis._registerLazyGuards(expandedDescriptors);\n\t\t\treturn super.initialize();\n\t\t}\n\n\t\t// \"block\" mode: load all modules, then initialize.\n\t\t// Guard against destroy() being called while modules are still loading.\n\t\tthis._loadAndRegisterGuards(expandedDescriptors)\n\t\t\t.then(() => {\n\t\t\t\tif (!this._destroyed) super.initialize();\n\t\t\t})\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tif (this._destroyed) return;\n\t\t\t\tLog.error(\n\t\t\t\t\t\"guardRouter.guards: module loading failed, initializing without manifest guards\",\n\t\t\t\t\tString(err),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tsuper.initialize();\n\t\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add a route dynamically and integrate it into pattern-tree inheritance.\n\t *\n\t * Appends the route name to the internal route list so that\n\t * `_collectRoutePatterns()` includes it in subsequent inheritance\n\t * lookups, clears the metadata cache, and registers any inherited\n\t * manifest guards when `inheritance` is `\"pattern-tree\"`.\n\t *\n\t * @param oConfig - Route configuration object as defined by `sap.ui.core.routing.Route`.\n\t * @param rest - Additional arguments forwarded to the parent `addRoute`.\n\t * @override sap.ui.core.routing.Router#addRoute\n\t * @since 1.6.0\n\t */\n\toverride addRoute(oConfig: $RouteSettings, ...rest: unknown[]): void {\n\t\t// @ts-expect-error -- oParent is required in the type declaration but optional at runtime\n\t\tsuper.addRoute(oConfig, ...rest);\n\n\t\t// Skip when called by the parent constructor before field initializers have run.\n\t\t// Routes from the constructor args are captured in _routeNames by the constructor body.\n\t\tif (!this._routeNames) return;\n\n\t\tconst name = oConfig.name;\n\t\tif (typeof name !== \"string\") return;\n\t\tif (this._routeNames.includes(name)) return;\n\n\t\tthis._routeNames.push(name);\n\t\tthis._resolvedMetaCache.clear();\n\n\t\tif (this._options.inheritance !== \"pattern-tree\") return;\n\t\tif (this._sourceDescriptors.length === 0) return;\n\n\t\tconst route = this.getRoute(name);\n\t\tif (!route) return;\n\t\tconst newPattern = route.getPattern();\n\t\tif (newPattern === undefined) return;\n\n\t\tconst newDescriptors = this._expandGuardDescriptorsForNewRoute(name, newPattern);\n\t\tif (newDescriptors.length === 0) return;\n\n\t\t// Always use lazy registration: if the module was loaded during\n\t\t// initialize() (block mode), the sync cache probe succeeds immediately.\n\t\t// This avoids an async gap between addRoute() and the first navigation.\n\t\tthis._registerLazyGuards(newDescriptors);\n\t}\n\n\t/**\n\t * Expand manifest guard descriptors for a single newly added route.\n\t *\n\t * For each source descriptor whose route is an ancestor of the new\n\t * route's pattern, emits a copy targeting the new route. Also emits\n\t * copies for existing routes that are descendants of the new route\n\t * (in case the new route has declared guards). Sorted by depth.\n\t */\n\tprivate _expandGuardDescriptorsForNewRoute(newName: string, newPattern: string): GuardDescriptor[] {\n\t\tconst result: GuardDescriptor[] = [];\n\n\t\tfor (const descriptor of this._sourceDescriptors) {\n\t\t\tif (descriptor.route === \"*\") continue;\n\n\t\t\tif (descriptor.route !== newName) {\n\t\t\t\t// Check if the source descriptor's route is an ancestor of the new route.\n\t\t\t\tconst ancestorRoute = this.getRoute(descriptor.route);\n\t\t\t\tconst ancestorPattern = ancestorRoute?.getPattern();\n\t\t\t\tif (ancestorPattern !== undefined && isPatternAncestor(ancestorPattern, newPattern)) {\n\t\t\t\t\tresult.push({ ...descriptor, route: newName });\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// The new route itself has a source descriptor: expand to existing descendants.\n\t\t\t\tfor (const { name, pattern } of this._collectRoutePatterns()) {\n\t\t\t\t\tif (name === newName) continue;\n\t\t\t\t\tif (isPatternAncestor(newPattern, pattern)) {\n\t\t\t\t\t\tresult.push({ ...descriptor, route: name });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Sort by pattern depth (ancestor guards run before descendant guards).\n\t\treturn result.toSorted((a, b) => {\n\t\t\tconst pa = this.getRoute(a.route)?.getPattern() ?? \"\";\n\t\t\tconst pb = this.getRoute(b.route)?.getPattern() ?? \"\";\n\t\t\treturn patternSegments(pa).length - patternSegments(pb).length;\n\t\t});\n\t}\n\n\t/**\n\t * Register a global guard that runs for every navigation.\n\t *\n\t * @param guard - Guard function to register. Non-functions are ignored with a warning.\n\t * @returns `this` for chaining.\n\t * @since 1.0.1\n\t */\n\taddGuard(guard: GuardFn): this {\n\t\tif (!this._isFn(guard, \"addGuard\")) return this;\n\t\tthis._pipeline.addGlobalGuard(guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove a previously registered global guard.\n\t *\n\t * @param guard - Guard function to remove by reference. Non-functions are ignored with a warning.\n\t * @returns `this` for chaining.\n\t * @since 1.0.1\n\t */\n\tremoveGuard(guard: GuardFn): this {\n\t\tif (!this._isFn(guard, \"removeGuard\")) return this;\n\t\tthis._pipeline.removeGlobalGuard(guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Register a guard for a specific route.\n\t *\n\t * Accepts either a guard function (registered as an enter guard) or a\n\t * configuration object with `beforeEnter` and/or `beforeLeave` guards.\n\t *\n\t * @param routeName - Route name as defined in `manifest.json`. If the route is unknown, the {@link GuardRouterOptions.unknownRouteRegistration} policy applies (default: warn).\n\t * @param guard - Guard function or {@link RouteGuardConfig} object.\n\t * @returns `this` for chaining.\n\t * @since 1.0.1\n\t */\n\taddRouteGuard(routeName: string, guard: GuardFn | RouteGuardConfig): this {\n\t\tif (isRouteGuardConfig(guard)) {\n\t\t\tif (!this._handleUnknownRouteRegistration(routeName, \"addRouteGuard\")) {\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tlet hasHandler = false;\n\n\t\t\tif (guard.beforeEnter !== undefined) {\n\t\t\t\thasHandler = true;\n\t\t\t\tif (this._isFn(guard.beforeEnter, \"addRouteGuard\", routeName)) {\n\t\t\t\t\tthis._pipeline.addEnterGuard(routeName, guard.beforeEnter);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (guard.beforeLeave !== undefined) {\n\t\t\t\thasHandler = true;\n\t\t\t\tif (this._isFn(guard.beforeLeave, \"addRouteGuard\", routeName)) {\n\t\t\t\t\tthis._pipeline.addLeaveGuard(routeName, guard.beforeLeave);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!hasHandler) {\n\t\t\t\tLog.info(\"addRouteGuard: config has no beforeEnter or beforeLeave\", routeName, LOG_COMPONENT);\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif (!this._isFn(guard, \"addRouteGuard\", routeName)) return this;\n\t\tif (!this._handleUnknownRouteRegistration(routeName, \"addRouteGuard\")) {\n\t\t\treturn this;\n\t\t}\n\t\tthis._pipeline.addEnterGuard(routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove a guard from a specific route.\n\t *\n\t * Accepts the same forms as `addRouteGuard`: a guard function removes\n\t * an enter guard; a configuration object removes `beforeEnter` and/or\n\t * `beforeLeave` by reference.\n\t *\n\t * @param routeName - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function or {@link RouteGuardConfig} object to remove by reference.\n\t * @returns `this` for chaining.\n\t * @since 1.0.1\n\t */\n\tremoveRouteGuard(routeName: string, guard: GuardFn | RouteGuardConfig): this {\n\t\tif (isRouteGuardConfig(guard)) {\n\t\t\tif (typeof guard.beforeEnter === \"function\") {\n\t\t\t\tthis.removeRouteGuard(routeName, guard.beforeEnter);\n\t\t\t}\n\t\t\tif (typeof guard.beforeLeave === \"function\") {\n\t\t\t\tthis.removeLeaveGuard(routeName, guard.beforeLeave);\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif (!this._isFn(guard, \"removeRouteGuard\", routeName)) return this;\n\t\tthis._pipeline.removeEnterGuard(routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Register a leave guard for a specific route.\n\t *\n\t * Leave guards run when navigating **away from** the route, before any\n\t * enter guards for the target route. They answer the binary question\n\t * \"can I leave?\" and return only a boolean (no redirects).\n\t *\n\t * @param routeName - Route name as defined in `manifest.json`. If the route is unknown, the {@link GuardRouterOptions.unknownRouteRegistration} policy applies (default: warn).\n\t * @param guard - Leave guard function to register. Non-functions are ignored with a warning.\n\t * @returns `this` for chaining.\n\t * @since 1.0.1\n\t */\n\taddLeaveGuard(routeName: string, guard: LeaveGuardFn): this {\n\t\tif (!this._isFn(guard, \"addLeaveGuard\", routeName)) return this;\n\t\tif (!this._handleUnknownRouteRegistration(routeName, \"addLeaveGuard\")) {\n\t\t\treturn this;\n\t\t}\n\t\tthis._pipeline.addLeaveGuard(routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Disambiguate the `navTo()` overload shapes into resolved arguments.\n\t *\n\t * UI5's native `navTo` has two signatures where the third parameter is either\n\t * `componentTargetInfo` (object) or `bReplace` (boolean). This method normalizes\n\t * both forms so the rest of `navTo` can work with a single set of variables.\n\t */\n\tprivate _resolveNavToArgs(\n\t\tcomponentTargetInfoOrReplace?: Record<string, ComponentTargetParameters> | boolean,\n\t\treplaceOrOptions?: boolean | GuardNavToOptions,\n\t\toptions?: GuardNavToOptions,\n\t): {\n\t\tcomponentTargetInfo?: Record<string, ComponentTargetParameters>;\n\t\treplace?: boolean;\n\t\tguardOptions?: GuardNavToOptions;\n\t} {\n\t\tif (typeof componentTargetInfoOrReplace === \"boolean\") {\n\t\t\t// Short form: navTo(name, params, replace, options?)\n\t\t\treturn {\n\t\t\t\treplace: componentTargetInfoOrReplace,\n\t\t\t\tguardOptions:\n\t\t\t\t\ttypeof replaceOrOptions === \"object\" && replaceOrOptions !== null ? replaceOrOptions : undefined,\n\t\t\t};\n\t\t}\n\t\t// Long form: navTo(name, params, componentTargetInfo, replace, options?)\n\t\treturn {\n\t\t\tcomponentTargetInfo: componentTargetInfoOrReplace,\n\t\t\treplace: typeof replaceOrOptions === \"boolean\" ? replaceOrOptions : undefined,\n\t\t\tguardOptions: options,\n\t\t};\n\t}\n\n\t/** Return `true` when the value is a function; otherwise log a warning. */\n\tprivate _isFn(value: unknown, method: string, detail?: string): boolean {\n\t\tif (typeof value === \"function\") return true;\n\t\tLog.warning(`${method}: not a function, ignoring`, detail, LOG_COMPONENT);\n\t\treturn false;\n\t}\n\n\t/**\n\t * Handle guard registration for a potentially unknown route.\n\t * Returns `true` if registration should proceed, `false` if not.\n\t */\n\tprivate _handleUnknownRouteRegistration(routeName: string, methodName: string): boolean {\n\t\tif (this.getRoute(routeName)) return true;\n\n\t\tswitch (this._options.unknownRouteRegistration) {\n\t\t\tcase \"ignore\":\n\t\t\t\treturn true;\n\t\t\tcase \"throw\":\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${methodName} called for unknown route \"${routeName}\". ` +\n\t\t\t\t\t\t`Set guardRouter.unknownRouteRegistration to \"warn\" or \"ignore\" to allow this.`,\n\t\t\t\t);\n\t\t\tcase \"warn\":\n\t\t\tdefault:\n\t\t\t\tLog.warning(`${methodName}: unknown route, guard registered anyway`, routeName, LOG_COMPONENT);\n\t\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * Remove a leave guard from a specific route.\n\t *\n\t * @param routeName - Route name as defined in `manifest.json`.\n\t * @param guard - Leave guard function to remove by reference. Non-functions are ignored with a warning.\n\t * @returns `this` for chaining.\n\t * @since 1.0.1\n\t */\n\tremoveLeaveGuard(routeName: string, guard: LeaveGuardFn): this {\n\t\tif (!this._isFn(guard, \"removeLeaveGuard\", routeName)) return this;\n\t\tthis._pipeline.removeLeaveGuard(routeName, guard);\n\t\treturn this;\n\t}\n\n\tprivate static readonly _EMPTY_META: Readonly<Record<string, unknown>> = Object.freeze({});\n\n\t/**\n\t * Return the resolved metadata for a route.\n\t *\n\t * When `inheritance` is `\"pattern-tree\"`, walks the ancestor chain and\n\t * shallow-merges metadata shallowest-first (child values win on conflict).\n\t * Both manifest and runtime metadata participate in inheritance.\n\t * The router caches results; {@link setRouteMeta} and `addRoute()` clear the cache.\n\t *\n\t * Logs a warning for unknown non-empty route names and returns an empty\n\t * frozen object. The empty string `\"\"` is treated as a valid root route.\n\t *\n\t * @param routeName - Route name as defined in `manifest.json`.\n\t * @returns Frozen record of metadata key-value pairs, or an empty frozen object if the route has no metadata.\n\t * @since 1.6.0\n\t */\n\tgetRouteMeta(routeName: string): Readonly<Record<string, unknown>> {\n\t\t// Empty string is a valid root route name (initial state before first navigation)\n\t\tif (routeName !== \"\" && !this.getRoute(routeName)) {\n\t\t\tLog.warning(\"getRouteMeta: unknown route, returning empty metadata\", routeName, LOG_COMPONENT);\n\t\t\treturn Router._EMPTY_META;\n\t\t}\n\n\t\t// Cache hit\n\t\tconst cached = this._resolvedMetaCache.get(routeName);\n\t\tif (cached) return cached;\n\n\t\tlet result: Readonly<Record<string, unknown>>;\n\n\t\tif (this._options.inheritance === \"pattern-tree\") {\n\t\t\tresult = this._resolveInheritedMeta(routeName);\n\t\t} else {\n\t\t\tresult = this._resolveFlatMeta(routeName);\n\t\t}\n\n\t\tif (Object.keys(result).length === 0) {\n\t\t\tthis._resolvedMetaCache.set(routeName, Router._EMPTY_META);\n\t\t\treturn Router._EMPTY_META;\n\t\t}\n\n\t\tthis._resolvedMetaCache.set(routeName, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Set runtime metadata for a route.\n\t *\n\t * Runtime metadata is merged on top of any manifest-declared metadata\n\t * when retrieved via {@link getRouteMeta}. When `inheritance` is\n\t * `\"pattern-tree\"`, descendant routes also see the updated values.\n\t * Invalidates the resolved-metadata cache. Non-object values are\n\t * ignored with a warning. Subject to the `unknownRouteRegistration` policy.\n\t *\n\t * @param routeName - Route name as defined in `manifest.json`.\n\t * @param meta - Plain object of metadata key-value pairs.\n\t * @returns `this` for chaining.\n\t * @since 1.6.0\n\t */\n\tsetRouteMeta(routeName: string, meta: Record<string, unknown>): this {\n\t\tif (!isRecord(meta)) {\n\t\t\tLog.warning(\"setRouteMeta: expected object, ignoring\", routeName, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\tif (routeName !== \"\" && !this._handleUnknownRouteRegistration(routeName, \"setRouteMeta\")) {\n\t\t\treturn this;\n\t\t}\n\t\tthis._runtimeMeta.set(routeName, Object.freeze({ ...meta }));\n\t\tthis._resolvedMetaCache.clear();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Return a Promise that settles when the current guard pipeline finishes.\n\t *\n\t * If a navigation is pending, the Promise resolves when that pipeline settles.\n\t * If no navigation is pending, it resolves immediately with the most recent\n\t * settlement result. Before any navigation has settled, it falls back to a\n\t * synthetic `Committed` result derived from the router's current route/hash\n\t * state. After `stop()`, that idle fallback reports empty route/hash values\n\t * until a new navigation settles.\n\t *\n\t * @returns Promise that resolves with a {@link NavigationResult} once the pipeline settles.\n\t * @since 1.2.0\n\t */\n\tnavigationSettled(): Promise<NavigationResult> {\n\t\tif (this._phase.kind !== \"evaluating\") {\n\t\t\treturn Promise.resolve(\n\t\t\t\tthis._lastSettlement ?? {\n\t\t\t\t\tstatus: NavigationOutcome.Committed,\n\t\t\t\t\troute: this._currentRoute,\n\t\t\t\t\thash: this._currentHash ?? \"\",\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\treturn new Promise((resolve) => {\n\t\t\tthis._settlementResolvers.push(resolve);\n\t\t});\n\t}\n\n\t/**\n\t * Attach an event handler for the `navigationSettled` event.\n\t *\n\t * Fires synchronously after every guard pipeline settlement with\n\t * a {@link NavigationResult} payload. Unlike the one-shot\n\t * `navigationSettled()` Promise, this event fires for every\n\t * navigation outcome without re-registration.\n\t *\n\t * @param oData - Application-specific payload passed to the handler as second argument.\n\t * @param fnFunction - The function to be called when the event occurs.\n\t * @param oListener - Context object to call the event handler with. Defaults to this Router.\n\t * @since 1.3.0\n\t */\n\tattachNavigationSettled(\n\t\toData: object,\n\t\tfnFunction: (evt: Router$NavigationSettledEvent) => void,\n\t\toListener?: object,\n\t): this;\n\tattachNavigationSettled(fnFunction: (evt: Router$NavigationSettledEvent) => void, oListener?: object): this;\n\tattachNavigationSettled(oData: unknown, fnFunction?: unknown, oListener?: unknown): this {\n\t\tthis.attachEvent(\n\t\t\t\"navigationSettled\",\n\t\t\toData as object,\n\t\t\tfnFunction as (...args: unknown[]) => void,\n\t\t\toListener as object,\n\t\t);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Detach a previously attached `navigationSettled` event handler.\n\t *\n\t * The passed parameters must match those used for registration with\n\t * {@link #attachNavigationSettled} beforehand.\n\t *\n\t * @param fnFunction - The handler function to detach.\n\t * @param oListener - Context object on which the given function had to be called.\n\t * @since 1.3.0\n\t */\n\tdetachNavigationSettled(fnFunction: (evt: Router$NavigationSettledEvent) => void, oListener?: object): this {\n\t\tthis.detachEvent(\"navigationSettled\", fnFunction as (...args: unknown[]) => void, oListener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Drain all settlement resolvers with the given result and fire\n\t * the `navigationSettled` event.\n\t */\n\tprivate _flushSettlement(result: NavigationResult): void {\n\t\tthis._lastSettlement = result;\n\t\tconst resolvers = this._settlementResolvers;\n\t\tthis._settlementResolvers = [];\n\t\tfor (const resolve of resolvers) {\n\t\t\tresolve(result);\n\t\t}\n\t\tthis.fireEvent(\"navigationSettled\", result);\n\t}\n\n\t/**\n\t * Navigate to a route with preflight guard evaluation.\n\t *\n\t * For programmatic navigation, guards run BEFORE the hash changes.\n\t * This prevents history pollution: blocked navigations never push a\n\t * history entry, and redirected navigations go directly to the final\n\t * target.\n\t *\n\t * Same-hash navigations are deduped: if the target hash matches\n\t * `_currentHash`, any pending navigation is cancelled and the call\n\t * returns without navigating. If it matches the in-flight attempt's\n\t * hash, the in-flight preflight continues undisturbed.\n\t *\n\t * When all guards are synchronous, the decision and the resulting\n\t * hash change happen in the same tick. When any guard returns a\n\t * Promise, `navTo()` returns `this` immediately and defers the\n\t * hash change to when the guard resolves.\n\t *\n\t * Assumes `super.navTo()` calls `HashChanger.setHash()` which fires\n\t * `hashChanged` synchronously, causing `parse()` to re-enter in the\n\t * same call stack (validated by test).\n\t *\n\t * @override sap.ui.core.routing.Router#navTo\n\t * @since 1.0.1\n\t */\n\toverride navTo(\n\t\trouteName: string,\n\t\tparameters?: object,\n\t\tcomponentTargetInfo?: Record<string, ComponentTargetParameters>,\n\t\tbReplace?: boolean,\n\t): this;\n\toverride navTo(routeName: string, parameters?: object, bReplace?: boolean): this;\n\toverride navTo(routeName: string, parameters?: object, bReplace?: boolean, options?: GuardNavToOptions): this;\n\toverride navTo(\n\t\trouteName: string,\n\t\tparameters?: object,\n\t\tcomponentTargetInfo?: Record<string, ComponentTargetParameters>,\n\t\tbReplace?: boolean,\n\t\toptions?: GuardNavToOptions,\n\t): this;\n\toverride navTo(\n\t\trouteName: string,\n\t\tparameters?: object,\n\t\tcomponentTargetInfoOrReplace?: Record<string, ComponentTargetParameters> | boolean,\n\t\treplaceOrOptions?: boolean | GuardNavToOptions,\n\t\toptions?: GuardNavToOptions,\n\t): this {\n\t\tconst { componentTargetInfo, replace, guardOptions } = this._resolveNavToArgs(\n\t\t\tcomponentTargetInfoOrReplace,\n\t\t\treplaceOrOptions,\n\t\t\toptions,\n\t\t);\n\n\t\t// Redirect path: _redirect() calls this.navTo() while in committing/redirect phase.\n\t\t// Bypass preflight -- parse() will commit directly via the committing phase.\n\t\tif (this._phase.kind === \"committing\" && this._phase.origin === \"redirect\") {\n\t\t\tsuper.navTo(routeName, parameters, componentTargetInfo, replace);\n\t\t\treturn this;\n\t\t}\n\n\t\t// Resolve the target hash so we can build a guard context.\n\t\t// getURL() returns the hash pattern with parameters substituted.\n\t\tconst route = this.getRoute(routeName);\n\t\tif (!route) {\n\t\t\t// Unknown route -- let parent handle it (may fire bypassed event).\n\t\t\t// Cancel any pending async navigation so settlement resolvers drain\n\t\t\t// and the stale pipeline does not commit a superseded navigation.\n\t\t\tthis._cancelPendingNavigation();\n\t\t\tsuper.navTo(routeName, parameters, componentTargetInfo, replace);\n\t\t\treturn this;\n\t\t}\n\n\t\tconst targetHash = route.getURL(parameters ?? {});\n\t\tconst routeInfo = this.getRouteInfoByHash(targetHash);\n\t\tconst toRoute = routeInfo?.name ?? \"\";\n\n\t\t// Same-hash dedup: cancel any pending navigation and return without navigating.\n\t\tif (this._currentHash !== null && targetHash === this._currentHash) {\n\t\t\tthis._cancelPendingNavigation();\n\t\t\treturn this;\n\t\t}\n\n\t\t// Pending-hash dedup: if an async preflight for this exact hash is\n\t\t// already running, don't cancel and restart it.\n\t\tif (this._phase.kind === \"evaluating\" && targetHash === this._phase.attempt.hash) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Cancel any pending navigation (including previous async preflight).\n\t\tthis._cancelPendingNavigation();\n\n\t\tconst skipGuards = guardOptions?.skipGuards === true;\n\n\t\t// Bypass mode: skip guards for programmatic navTo() -- commit directly.\n\t\tif (skipGuards || this._options.navToPreflight === \"bypass\") {\n\t\t\tthis._phase = { kind: \"committing\", hash: targetHash, route: toRoute, origin: \"preflight\" };\n\t\t\tsuper.navTo(routeName, parameters, componentTargetInfo, replace);\n\t\t\t// Safety: if super.navTo didn't trigger parse (e.g. hash didn't change),\n\t\t\t// clear the marker to avoid stale state.\n\t\t\tif (this._phase.kind === \"committing\" && this._phase.hash === targetHash) {\n\t\t\t\tthis._commitNavigation(targetHash, toRoute);\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\t// Off mode: defer guard evaluation to parse() fallback.\n\t\tif (this._options.navToPreflight === \"off\") {\n\t\t\tsuper.navTo(routeName, parameters, componentTargetInfo, replace);\n\t\t\treturn this;\n\t\t}\n\n\t\t// Default \"guard\" mode: evaluate guards before hash change.\n\t\tconst controller = new AbortController();\n\t\tconst generation = this._parseGeneration;\n\n\t\tthis._phase = {\n\t\t\tkind: \"evaluating\",\n\t\t\tattempt: { hash: targetHash, route: toRoute, controller, generation },\n\t\t};\n\n\t\tconst context = this._createGuardContext(toRoute, targetHash, routeInfo, controller.signal);\n\n\t\tconst decision = this._pipeline.evaluate(context);\n\n\t\tif (isPromiseLike(decision)) {\n\t\t\tdecision\n\t\t\t\t.then((d: GuardDecision) => {\n\t\t\t\t\tif (generation !== this._parseGeneration || this._phase.kind !== \"evaluating\") {\n\t\t\t\t\t\tLog.debug(\n\t\t\t\t\t\t\t\"Async preflight result discarded (superseded by newer navigation)\",\n\t\t\t\t\t\t\ttargetHash,\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tthis._applyPreflightDecision(\n\t\t\t\t\t\td,\n\t\t\t\t\t\trouteName,\n\t\t\t\t\t\tparameters,\n\t\t\t\t\t\tcomponentTargetInfo,\n\t\t\t\t\t\treplace,\n\t\t\t\t\t\ttargetHash,\n\t\t\t\t\t\ttoRoute,\n\t\t\t\t\t\tcontext.bag,\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\t// Only check generation here, not phase. If _redirect threw and its\n\t\t\t\t\t// finally already reset phase to idle, we still need to drain\n\t\t\t\t\t// settlement resolvers via _errorNavigation.\n\t\t\t\t\tif (generation !== this._parseGeneration) return;\n\t\t\t\t\tLog.error(\n\t\t\t\t\t\t`Async preflight guard failed for route \"${routeName}\", navigation failed`,\n\t\t\t\t\t\tString(error),\n\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t);\n\t\t\t\t\tthis._errorNavigation(error, targetHash, false);\n\t\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\t// Sync path: apply the decision immediately.\n\t\tthis._applyPreflightDecision(\n\t\t\tdecision,\n\t\t\trouteName,\n\t\t\tparameters,\n\t\t\tcomponentTargetInfo,\n\t\t\treplace,\n\t\t\ttargetHash,\n\t\t\ttoRoute,\n\t\t\tcontext.bag,\n\t\t);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Apply a preflight guard decision. For \"allow\", enter the committing\n\t * phase and call super.navTo(). For \"block\", flush settlement without\n\t * touching the hash. For \"redirect\", start a redirect chain.\n\t * For \"error\", flush Error settlement with the guard's error.\n\t *\n\t * @param decision - Normalized guard pipeline result.\n\t * @param routeName - Original route name passed to navTo().\n\t * @param parameters - Original route parameters.\n\t * @param componentTargetInfo - Optional component target info from the navTo() overload.\n\t * @param bReplace - Whether to replace the current history entry.\n\t * @param targetHash - Resolved hash for the target route.\n\t * @param toRoute - Resolved route name (may differ from routeName for nested routes).\n\t */\n\tprivate _applyPreflightDecision(\n\t\tdecision: GuardDecision,\n\t\trouteName: string,\n\t\tparameters: object | undefined,\n\t\tcomponentTargetInfo: Record<string, ComponentTargetParameters> | undefined,\n\t\tbReplace: boolean | undefined,\n\t\ttargetHash: string,\n\t\ttoRoute: string,\n\t\tbag: Map<string, unknown>,\n\t): void {\n\t\tswitch (decision.action) {\n\t\t\tcase \"allow\":\n\t\t\t\tthis._phase = { kind: \"committing\", hash: targetHash, route: toRoute, origin: \"preflight\" };\n\t\t\t\tsuper.navTo(routeName, parameters, componentTargetInfo, bReplace);\n\t\t\t\t// Safety: if super.navTo didn't trigger parse (e.g. hash didn't change),\n\t\t\t\t// clear the marker to avoid stale state.\n\t\t\t\tif (this._phase.kind === \"committing\" && this._phase.hash === targetHash) {\n\t\t\t\t\t// Hash didn't change, so parse() wasn't called. Commit manually.\n\t\t\t\t\tthis._commitNavigation(targetHash, toRoute);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"block\":\n\t\t\t\tthis._blockNavigation(targetHash, false);\n\t\t\t\tbreak;\n\t\t\tcase \"redirect\":\n\t\t\t\tthis._startRedirectChain(decision.target, targetHash, false, bag);\n\t\t\t\tbreak;\n\t\t\tcase \"error\":\n\t\t\t\tthis._errorNavigation(decision.error, targetHash, false);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Intercept hash changes and run the guard pipeline before route matching.\n\t *\n\t * Called by the HashChanger on every `hashChanged` event. Runs leave guards\n\t * (current route), then global + route-specific enter guards (target route).\n\t * Stays synchronous when all guards return plain values; falls back to async\n\t * when a guard returns a Promise. A generation counter discards stale results\n\t * when navigations overlap.\n\t *\n\t * @param newHash - The new hash fragment from the URL.\n\t * @override sap.ui.core.routing.Router#parse\n\t * @since 1.0.1\n\t */\n\toverride parse(newHash: string): void {\n\t\tif (this._suppressedHash !== null) {\n\t\t\tif (newHash === this._suppressedHash) {\n\t\t\t\tthis._suppressedHash = null;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._suppressedHash = null;\n\t\t}\n\n\t\tif (this._phase.kind === \"committing\") {\n\t\t\tthis._commitNavigation(\n\t\t\t\tnewHash,\n\t\t\t\tthis._phase.route !== \"\" ? this._phase.route : (this.getRouteInfoByHash(newHash)?.name ?? \"\"),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._currentHash !== null && newHash === this._currentHash) {\n\t\t\tthis._cancelPendingNavigation();\n\t\t\treturn;\n\t\t}\n\n\t\tconst routeInfo = this.getRouteInfoByHash(newHash);\n\t\tconst toRoute = routeInfo?.name ?? \"\";\n\n\t\tthis._cancelPendingNavigation();\n\n\t\tconst controller = new AbortController();\n\t\tconst generation = this._parseGeneration;\n\n\t\tthis._phase = {\n\t\t\tkind: \"evaluating\",\n\t\t\tattempt: { hash: newHash, route: toRoute, controller, generation },\n\t\t};\n\n\t\tconst context = this._createGuardContext(toRoute, newHash, routeInfo, controller.signal);\n\n\t\tconst decision = this._pipeline.evaluate(context);\n\n\t\tif (isPromiseLike(decision)) {\n\t\t\tdecision\n\t\t\t\t.then((d: GuardDecision) => {\n\t\t\t\t\tif (generation !== this._parseGeneration || this._phase.kind !== \"evaluating\") {\n\t\t\t\t\t\tLog.debug(\n\t\t\t\t\t\t\t\"Async guard result discarded (superseded by newer navigation)\",\n\t\t\t\t\t\t\tnewHash,\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tthis._applyDecision(d, newHash, toRoute, context.bag);\n\t\t\t\t})\n\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\t// Only check generation here, not phase. If _redirect threw and its\n\t\t\t\t\t// finally already reset phase to idle, we still need to drain\n\t\t\t\t\t// settlement resolvers via _errorNavigation.\n\t\t\t\t\tif (generation !== this._parseGeneration) return;\n\t\t\t\t\tLog.error(\n\t\t\t\t\t\t`Guard pipeline failed for \"${newHash}\", navigation failed`,\n\t\t\t\t\t\tString(error),\n\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t);\n\t\t\t\t\tthis._errorNavigation(error, newHash);\n\t\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tthis._applyDecision(decision, newHash, toRoute, context.bag);\n\t}\n\n\t/**\n\t * Stop listening to hash changes and reset guard state.\n\t *\n\t * Resets `_currentRoute` and `_currentHash` so that a subsequent\n\t * `initialize()` re-parses the current hash and fires `routeMatched`,\n\t * matching the native `sap.m.routing.Router` behavior.\n\t *\n\t * @override sap.ui.core.routing.Router#stop\n\t * @since 1.0.1\n\t */\n\toverride stop(): this {\n\t\t// Cancel first so in-flight navigationSettled() resolvers receive the\n\t\t// Cancelled result before _lastSettlement is cleared below.\n\t\tthis._cancelPendingNavigation();\n\t\tthis._suppressedHash = null;\n\t\tthis._currentRoute = \"\";\n\t\tthis._currentHash = null;\n\t\tthis._lastSettlement = null;\n\t\tsuper.stop();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Invalidate any in-flight async guard work. Bumps the generation counter\n\t * so pending `.then()` callbacks see they are stale, aborts the signal,\n\t * and transitions to idle.\n\t */\n\tprivate _cancelPendingNavigation(): void {\n\t\t++this._parseGeneration;\n\t\tif (this._phase.kind === \"evaluating\") {\n\t\t\tthis._phase.attempt.controller.abort();\n\t\t\tthis._flushSettlement({\n\t\t\t\tstatus: NavigationOutcome.Cancelled,\n\t\t\t\troute: this._currentRoute,\n\t\t\t\thash: this._currentHash ?? \"\",\n\t\t\t});\n\t\t}\n\t\tthis._phase = IDLE;\n\t}\n\n\t/**\n\t * Apply a guard decision for the parse() fallback path.\n\t */\n\tprivate _applyDecision(decision: GuardDecision, hash: string, route: string, bag: Map<string, unknown>): void {\n\t\tswitch (decision.action) {\n\t\t\tcase \"allow\":\n\t\t\t\tthis._phase = { kind: \"committing\", hash, route, origin: \"parse\" };\n\t\t\t\tthis._commitNavigation(hash, route);\n\t\t\t\tbreak;\n\t\t\tcase \"block\":\n\t\t\t\tthis._blockNavigation(hash);\n\t\t\t\tbreak;\n\t\t\tcase \"redirect\":\n\t\t\t\tthis._startRedirectChain(decision.target, hash, true, bag);\n\t\t\t\tbreak;\n\t\t\tcase \"error\":\n\t\t\t\tthis._errorNavigation(decision.error, hash);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Delegate to the parent router and update internal state.\n\t *\n\t * State is updated BEFORE calling parse to ensure that if event handlers\n\t * (e.g., routeMatched) trigger nested navigation, the leave guards will\n\t * run for the correct (new) route rather than the old one.\n\t */\n\tprivate _commitNavigation(hash: string, route?: string): void {\n\t\tconst wasRedirect = this._phase.kind === \"committing\" && this._phase.origin === \"redirect\";\n\t\tthis._currentHash = hash;\n\t\tthis._currentRoute = route ?? this.getRouteInfoByHash(hash)?.name ?? \"\";\n\t\t// Transition to idle before super.parse so that routeMatched/patternMatched\n\t\t// handlers that call navTo() go through the full guard pipeline.\n\t\tthis._phase = IDLE;\n\t\tthis._flushSettlement({\n\t\t\tstatus: wasRedirect\n\t\t\t\t? NavigationOutcome.Redirected\n\t\t\t\t: this._currentRoute === \"\"\n\t\t\t\t\t? NavigationOutcome.Bypassed\n\t\t\t\t\t: NavigationOutcome.Committed,\n\t\t\troute: this._currentRoute,\n\t\t\thash,\n\t\t});\n\t\tsuper.parse(hash);\n\t}\n\n\t/**\n\t * Evaluate guards on a redirect target and apply the resulting decision.\n\t *\n\t * Handles loop detection (visited-hash set + depth cap), unknown-route\n\t * fallback, sync/async guard evaluation, and recursive chaining when\n\t * the target's guard itself returns a redirect. All hops in a chain\n\t * share the same AbortSignal and generation counter from the original\n\t * navigation so that a superseding navigation correctly discards\n\t * in-flight redirect work.\n\t *\n\t * @param target - Redirect target: a route name string or {@link GuardRedirect} with parameters.\n\t * @param chain - Mutable context threaded through the redirect chain (visited set, signals, etc.).\n\t */\n\tprivate _redirect(target: string | GuardRedirect, chain: RedirectChainContext): void {\n\t\tconst targetName = typeof target === \"string\" ? target : target.route;\n\t\tlet targetHash: string | null = null;\n\t\tconst targetParameters = typeof target === \"string\" ? {} : (target.parameters ?? {});\n\t\tconst targetRoute = this.getRoute(targetName);\n\t\tif (targetRoute) {\n\t\t\ttry {\n\t\t\t\ttargetHash = targetRoute.getURL(targetParameters);\n\t\t\t} catch {\n\t\t\t\ttargetHash = null;\n\t\t\t}\n\t\t}\n\n\t\t// Loop detection: visited set (exact hash match) + depth cap.\n\t\tif (targetHash !== null && chain.visited.has(targetHash)) {\n\t\t\tLog.error(\n\t\t\t\t`Guard redirect loop detected: ${[...chain.visited, targetHash].join(\" -> \")}`,\n\t\t\t\tundefined,\n\t\t\t\tLOG_COMPONENT,\n\t\t\t);\n\t\t\tthis._blockNavigation(chain.attemptedHash, chain.restoreHash);\n\t\t\treturn;\n\t\t}\n\t\tif (chain.visited.size > MAX_REDIRECT_DEPTH) {\n\t\t\tLog.error(\n\t\t\t\t`Guard redirect chain exceeded maximum depth (${MAX_REDIRECT_DEPTH}): ${[...chain.visited].join(\" -> \")}`,\n\t\t\t\tundefined,\n\t\t\t\tLOG_COMPONENT,\n\t\t\t);\n\t\t\tthis._blockNavigation(chain.attemptedHash, chain.restoreHash);\n\t\t\treturn;\n\t\t}\n\t\tif (targetHash !== null) {\n\t\t\tchain.visited.add(targetHash);\n\t\t}\n\n\t\t// If the target route doesn't exist or the hash couldn't be resolved,\n\t\t// attempt navTo (parent may fire bypassed) and fall back to blocked.\n\t\tif (targetHash === null) {\n\t\t\tconst settlementBefore = this._lastSettlement;\n\t\t\tthis._phase = { kind: \"committing\", hash: \"\", route: targetName, origin: \"redirect\" };\n\t\t\ttry {\n\t\t\t\tif (typeof target === \"string\") {\n\t\t\t\t\tthis.navTo(target, {}, {}, true);\n\t\t\t\t} else {\n\t\t\t\t\tthis.navTo(target.route, target.parameters ?? {}, target.componentTargetInfo, true);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tif (this._phase.kind === \"committing\") {\n\t\t\t\t\tthis._phase = IDLE;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this._lastSettlement === settlementBefore) {\n\t\t\t\tLog.warning(\n\t\t\t\t\t`Guard redirect target \"${targetName}\" did not produce a navigation, treating as blocked`,\n\t\t\t\t\tundefined,\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tthis._blockNavigation(chain.attemptedHash, chain.restoreHash);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Narrowed after the null-branch early return; const carries it into the async closure.\n\t\tconst resolvedHash: string = targetHash;\n\n\t\t// Build guard context for the redirect target.\n\t\tconst routeInfo = this.getRouteInfoByHash(resolvedHash);\n\t\tconst context: GuardContext = {\n\t\t\ttoRoute: routeInfo?.name ?? \"\",\n\t\t\ttoHash: resolvedHash,\n\t\t\ttoArguments: routeInfo?.arguments ?? {},\n\t\t\tfromRoute: chain.fromRoute,\n\t\t\tfromHash: chain.fromHash,\n\t\t\tsignal: chain.signal,\n\t\t\tbag: chain.bag,\n\t\t\ttoMeta: this.getRouteMeta(routeInfo?.name ?? \"\"),\n\t\t\tfromMeta: this.getRouteMeta(chain.fromRoute),\n\t\t};\n\n\t\tconst decision = this._pipeline.evaluate(context, { skipLeaveGuards: true });\n\n\t\tif (isPromiseLike(decision)) {\n\t\t\tdecision\n\t\t\t\t.then((d: GuardDecision) => {\n\t\t\t\t\tif (chain.generation !== this._parseGeneration) return;\n\t\t\t\t\tthis._applyRedirectDecision(d, target, resolvedHash, chain);\n\t\t\t\t})\n\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\tif (chain.generation !== this._parseGeneration) return;\n\t\t\t\t\tLog.error(\n\t\t\t\t\t\t`Guard pipeline failed during redirect chain for \"${targetName}\", navigation failed`,\n\t\t\t\t\t\tString(error),\n\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t);\n\t\t\t\t\tthis._errorNavigation(error, chain.attemptedHash, chain.restoreHash);\n\t\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tthis._applyRedirectDecision(decision, target, resolvedHash, chain);\n\t}\n\n\t/**\n\t * Apply a guard decision within a redirect chain. For \"allow\", enter\n\t * committing phase and delegate to navTo (which hits the existing bypass).\n\t * For \"block\", block the entire chain. For \"redirect\", recurse.\n\t *\n\t * @param decision - Normalized guard pipeline result for this hop.\n\t * @param target - The redirect target (route name or {@link GuardRedirect}).\n\t * @param targetHash - Resolved hash for the redirect target (guaranteed non-null).\n\t * @param chain - Shared redirect chain context with visited set, signals, etc.\n\t */\n\tprivate _applyRedirectDecision(\n\t\tdecision: GuardDecision,\n\t\ttarget: string | GuardRedirect,\n\t\ttargetHash: string,\n\t\tchain: RedirectChainContext,\n\t): void {\n\t\tswitch (decision.action) {\n\t\t\tcase \"allow\": {\n\t\t\t\tconst targetName = typeof target === \"string\" ? target : target.route;\n\t\t\t\tconst settlementBefore = this._lastSettlement;\n\t\t\t\tthis._phase = { kind: \"committing\", hash: targetHash, route: targetName, origin: \"redirect\" };\n\t\t\t\ttry {\n\t\t\t\t\tif (typeof target === \"string\") {\n\t\t\t\t\t\tthis.navTo(target, {}, {}, true);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.navTo(target.route, target.parameters ?? {}, target.componentTargetInfo, true);\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tif (this._phase.kind === \"committing\") {\n\t\t\t\t\t\tthis._phase = IDLE;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Safety net: if navTo didn't produce a settlement (e.g. unknown route\n\t\t\t\t// or redirect to current hash where HashChanger doesn't fire), handle it.\n\t\t\t\tif (this._lastSettlement === settlementBefore) {\n\t\t\t\t\tconst redirectsToCurrentHash = targetHash === (this._currentHash ?? \"\");\n\t\t\t\t\tif (redirectsToCurrentHash) {\n\t\t\t\t\t\tthis._phase = {\n\t\t\t\t\t\t\tkind: \"committing\",\n\t\t\t\t\t\t\thash: this._currentHash ?? \"\",\n\t\t\t\t\t\t\troute: this._currentRoute,\n\t\t\t\t\t\t\torigin: \"redirect\",\n\t\t\t\t\t\t};\n\t\t\t\t\t\tthis._commitNavigation(this._currentHash ?? \"\", this._currentRoute);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tLog.warning(\n\t\t\t\t\t\t`Guard redirect target \"${targetName}\" did not produce a navigation, treating as blocked`,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t);\n\t\t\t\t\tthis._blockNavigation(chain.attemptedHash, chain.restoreHash);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"block\":\n\t\t\t\tthis._blockNavigation(chain.attemptedHash, chain.restoreHash);\n\t\t\t\tbreak;\n\t\t\tcase \"redirect\":\n\t\t\t\tthis._redirect(decision.target, chain);\n\t\t\t\tbreak;\n\t\t\tcase \"error\":\n\t\t\t\tthis._errorNavigation(decision.error, chain.attemptedHash, chain.restoreHash);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Build a guard context for a new navigation.\n\t * Called by {@link navTo} (preflight path) and {@link parse} (browser-initiated path).\n\t */\n\tprivate _createGuardContext(\n\t\ttoRoute: string,\n\t\ttoHash: string,\n\t\trouteInfo: { arguments: Record<string, string | Record<string, string>> } | undefined,\n\t\tsignal: AbortSignal,\n\t): GuardContext {\n\t\treturn {\n\t\t\ttoRoute,\n\t\t\ttoHash,\n\t\t\ttoArguments: routeInfo?.arguments ?? {},\n\t\t\tfromRoute: this._currentRoute,\n\t\t\tfromHash: this._currentHash ?? \"\",\n\t\t\tsignal,\n\t\t\tbag: new Map(),\n\t\t\ttoMeta: this.getRouteMeta(toRoute),\n\t\t\tfromMeta: this.getRouteMeta(this._currentRoute),\n\t\t};\n\t}\n\n\t/**\n\t * Start a new redirect chain from the current evaluating phase.\n\t * Called by {@link _applyPreflightDecision} and {@link _applyDecision}\n\t * when a guard returns a redirect. Delegates to {@link _redirect} with\n\t * a fresh {@link RedirectChainContext}.\n\t */\n\tprivate _startRedirectChain(\n\t\ttarget: string | GuardRedirect,\n\t\thash: string,\n\t\trestoreHash: boolean,\n\t\tbag: Map<string, unknown>,\n\t): void {\n\t\tconst { attempt } = this._phase as PhaseEvaluating;\n\t\tconst visited = new Set<string>();\n\t\tvisited.add(hash);\n\t\tthis._redirect(target, {\n\t\t\tvisited,\n\t\t\tattemptedHash: hash,\n\t\t\trestoreHash,\n\t\t\tfromRoute: this._currentRoute,\n\t\t\tfromHash: this._currentHash ?? \"\",\n\t\t\tsignal: attempt.controller.signal,\n\t\t\tgeneration: attempt.generation,\n\t\t\tbag,\n\t\t});\n\t}\n\n\t/**\n\t * Clear pending state and flush a Blocked settlement.\n\t * When `restoreHash` is true (default), also restores the browser hash\n\t * to `_currentHash`. Preflight callers pass false because the hash was\n\t * never changed.\n\t */\n\tprivate _blockNavigation(attemptedHash?: string, restoreHash = true): void {\n\t\tthis._phase = IDLE;\n\t\tthis._flushSettlement({\n\t\t\tstatus: NavigationOutcome.Blocked,\n\t\t\troute: this._currentRoute,\n\t\t\thash: this._currentHash ?? \"\",\n\t\t});\n\t\tthis._restoreHashIfNeeded(attemptedHash, restoreHash);\n\t}\n\n\t/**\n\t * Clear pending state and flush an Error settlement.\n\t * Same structure as {@link _blockNavigation} but with `NavigationOutcome.Error`\n\t * and the error that caused the failure.\n\t */\n\tprivate _errorNavigation(error: unknown, attemptedHash?: string, restoreHash = true): void {\n\t\tthis._phase = IDLE;\n\t\tthis._flushSettlement({\n\t\t\tstatus: NavigationOutcome.Error,\n\t\t\troute: this._currentRoute,\n\t\t\thash: this._currentHash ?? \"\",\n\t\t\terror,\n\t\t});\n\t\tthis._restoreHashIfNeeded(attemptedHash, restoreHash);\n\t}\n\n\t/** Conditionally restore the browser hash after a blocked or errored navigation. */\n\tprivate _restoreHashIfNeeded(attemptedHash: string | undefined, restoreHash: boolean): void {\n\t\tif (!restoreHash) return;\n\t\tif (this._currentHash === null && attemptedHash && attemptedHash !== \"\") {\n\t\t\tthis._restoreHash(\"\", false);\n\t\t\treturn;\n\t\t}\n\t\tthis._restoreHash(this._currentHash ?? \"\");\n\t}\n\n\t/**\n\t * Restore the previous hash without creating a history entry.\n\t * Assumes replaceHash fires hashChanged synchronously (validated by test).\n\t * `_currentRoute` stays unchanged because the navigation never\n\t * committed. The user remains on the same logical route.\n\t */\n\tprivate _restoreHash(hash: string, suppressParse = true): void {\n\t\tconst hashChanger = this.getHashChanger();\n\t\tif (hashChanger) {\n\t\t\tthis._suppressedHash = suppressParse ? hash : null;\n\t\t\thashChanger.replaceHash(hash, HistoryDirection.Unknown);\n\t\t\tif (this._suppressedHash === hash) {\n\t\t\t\tthis._suppressedHash = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Collect all route names and their patterns from the router.\n\t * Skips routes whose pattern is undefined (no pattern configured).\n\t */\n\tprivate _collectRoutePatterns(): { name: string; pattern: string }[] {\n\t\tconst result: { name: string; pattern: string }[] = [];\n\t\tfor (const name of this._routeNames) {\n\t\t\tconst route = this.getRoute(name);\n\t\t\tif (route) {\n\t\t\t\tconst pattern = route.getPattern();\n\t\t\t\tif (pattern !== undefined) {\n\t\t\t\t\tresult.push({ name, pattern });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Expand guard descriptors to descendant routes when guard inheritance\n\t * is set to `\"pattern-tree\"`. Global (`\"*\"`) descriptors are kept as-is.\n\t * Descriptors are sorted by pattern depth (ancestor guards run before\n\t * descendant guards).\n\t */\n\tprivate _expandGuardDescriptors(descriptors: GuardDescriptor[]): GuardDescriptor[] {\n\t\tconst allRoutes = this._collectRoutePatterns();\n\t\tif (allRoutes.length === 0) return descriptors;\n\n\t\t// Build a name -> pattern map for quick lookup\n\t\tconst patternByName = new Map(allRoutes.map((r) => [r.name, r.pattern]));\n\n\t\tconst expanded: GuardDescriptor[] = [];\n\n\t\tfor (const descriptor of descriptors) {\n\t\t\texpanded.push(descriptor);\n\n\t\t\t// Global guards and routes without a known pattern are not expanded\n\t\t\tif (descriptor.route === \"*\") continue;\n\t\t\tconst ancestorPattern = patternByName.get(descriptor.route);\n\t\t\tif (ancestorPattern === undefined) continue;\n\n\t\t\t// Find descendant routes whose pattern extends the ancestor's pattern\n\t\t\tfor (const { name, pattern } of allRoutes) {\n\t\t\t\tif (name === descriptor.route) continue;\n\t\t\t\tif (isPatternAncestor(ancestorPattern, pattern)) {\n\t\t\t\t\texpanded.push({ ...descriptor, route: name });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Sort by pattern depth (segment count) so ancestor guards run first.\n\t\t// Global (\"*\") descriptors return 0 here -- their relative position is irrelevant\n\t\t// because GuardPipeline evaluates globals separately from route-specific guards.\n\t\t// oxlint-disable-next-line unicorn/no-array-sort -- expanded is a local array, mutation is intentional\n\t\treturn expanded.sort((a, b) => {\n\t\t\tif (a.route === \"*\" || b.route === \"*\") return 0;\n\t\t\tconst pa = patternByName.get(a.route) ?? \"\";\n\t\t\tconst pb = patternByName.get(b.route) ?? \"\";\n\t\t\treturn patternSegments(pa).length - patternSegments(pb).length;\n\t\t});\n\t}\n\n\t/**\n\t * Resolve metadata for a route without inheritance (flat merge of\n\t * manifest and runtime metadata).\n\t */\n\tprivate _resolveFlatMeta(routeName: string): Readonly<Record<string, unknown>> {\n\t\tconst manifest = this._manifestMeta.get(routeName);\n\t\tconst runtime = this._runtimeMeta.get(routeName);\n\t\tif (!manifest && !runtime) return Router._EMPTY_META;\n\t\tif (!runtime) return manifest ?? Router._EMPTY_META;\n\t\tif (!manifest) return Object.freeze({ ...runtime });\n\t\treturn Object.freeze({ ...manifest, ...runtime });\n\t}\n\n\t/**\n\t * Resolve metadata for a route with pattern-tree inheritance.\n\t * Walks ancestor patterns shallowest-first, merging manifest and\n\t * runtime metadata at each level, then overlays the route's own.\n\t */\n\tprivate _resolveInheritedMeta(routeName: string): Readonly<Record<string, unknown>> {\n\t\tconst allRoutes = this._collectRoutePatterns();\n\t\tconst routeEntry = allRoutes.find((r) => r.name === routeName);\n\t\tif (!routeEntry) return this._resolveFlatMeta(routeName);\n\n\t\t// Find ancestors that have declared metadata (manifest or runtime)\n\t\tconst ancestors = allRoutes.filter(\n\t\t\t(r) =>\n\t\t\t\tr.name !== routeName &&\n\t\t\t\t(this._manifestMeta.has(r.name) || this._runtimeMeta.has(r.name)) &&\n\t\t\t\tisPatternAncestor(r.pattern, routeEntry.pattern),\n\t\t);\n\t\t// oxlint-disable-next-line unicorn/no-array-sort -- ancestors is a fresh array from filter()\n\t\tancestors.sort((a, b) => patternSegments(a.pattern).length - patternSegments(b.pattern).length);\n\n\t\t// Merge shallowest-first: root ancestor -> deeper ancestors -> own manifest -> own runtime\n\t\tconst merged: Record<string, unknown> = {};\n\n\t\tfor (const ancestor of ancestors) {\n\t\t\tconst ancestorManifest = this._manifestMeta.get(ancestor.name);\n\t\t\tif (ancestorManifest) Object.assign(merged, ancestorManifest);\n\t\t\tconst ancestorRuntime = this._runtimeMeta.get(ancestor.name);\n\t\t\tif (ancestorRuntime) Object.assign(merged, ancestorRuntime);\n\t\t}\n\n\t\tconst ownManifest = this._manifestMeta.get(routeName);\n\t\tif (ownManifest) Object.assign(merged, ownManifest);\n\t\tconst ownRuntime = this._runtimeMeta.get(routeName);\n\t\tif (ownRuntime) Object.assign(merged, ownRuntime);\n\n\t\tif (Object.keys(merged).length === 0) return Router._EMPTY_META;\n\t\treturn Object.freeze(merged);\n\t}\n\n\t/**\n\t * Load guard modules individually via `sap.ui.require` and register\n\t * each resolved function with the appropriate guard API.\n\t *\n\t * Each module is loaded in its own `sap.ui.require` call so that a\n\t * single invalid path only skips that guard (with a warning) rather\n\t * than failing the entire batch. Once all loads settle, guards\n\t * register in declaration order. Registration errors (e.g. from\n\t * `unknownRouteRegistration: \"throw\"`) are caught per-module.\n\t */\n\tprivate _loadAndRegisterGuards(descriptors: GuardDescriptor[]): Promise<void> {\n\t\tconst promises = descriptors.map((descriptor) => {\n\t\t\treturn new Promise<{ descriptor: GuardDescriptor; moduleExport: unknown }>((resolve) => {\n\t\t\t\tsap.ui.require(\n\t\t\t\t\t[descriptor.modulePath],\n\t\t\t\t\t(moduleExport: unknown) => {\n\t\t\t\t\t\tresolve({ descriptor, moduleExport });\n\t\t\t\t\t},\n\t\t\t\t\t(err: Error) => {\n\t\t\t\t\t\tLog.warning(\n\t\t\t\t\t\t\t`guardRouter.guards: failed to load module \"${descriptor.modulePath}\", skipping`,\n\t\t\t\t\t\t\tString(err),\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tresolve({ descriptor, moduleExport: null });\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\t\treturn Promise.all(promises).then((results) => {\n\t\t\tfor (const { descriptor, moduleExport } of results) {\n\t\t\t\tif (moduleExport === null) continue;\n\t\t\t\tconst exports = resolveModuleExports(\n\t\t\t\t\tmoduleExport,\n\t\t\t\t\tdescriptor.modulePath,\n\t\t\t\t\tdescriptor.name,\n\t\t\t\t\tdescriptor.exportKey,\n\t\t\t\t);\n\t\t\t\tfor (const { fn } of exports) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis._registerGuardFromDescriptor(descriptor, fn);\n\t\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\t\tLog.error(\n\t\t\t\t\t\t\t`guardRouter.guards: failed to register \"${descriptor.modulePath}\"`,\n\t\t\t\t\t\t\tString(err),\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Route a parsed guard descriptor to the correct registration method.\n\t */\n\tprivate _registerGuardFromDescriptor(descriptor: GuardDescriptor, guardFn: GuardFn): void {\n\t\tif (descriptor.route === \"*\") {\n\t\t\tthis.addGuard(guardFn);\n\t\t} else if (descriptor.type === \"leave\") {\n\t\t\tif (!this._handleUnknownRouteRegistration(descriptor.route, \"addLeaveGuard\")) return;\n\t\t\tthis._pipeline.addLeaveGuard(descriptor.route, guardFn);\n\t\t} else {\n\t\t\tthis.addRouteGuard(descriptor.route, guardFn);\n\t\t}\n\t}\n\n\t/**\n\t * Register lazy wrapper functions that load guard modules on first use.\n\t *\n\t * Cherry-picked descriptors (with exportKey) get one lazy wrapper each.\n\t * Bare-path descriptors try a sync cache probe first; if the module is\n\t * cached (preload likely finished), all guards are expanded immediately.\n\t * On cache miss, a single \"expander\" wrapper loads the module on first\n\t * navigation, registers remaining guards, and executes the first.\n\t */\n\tprivate _registerLazyGuards(descriptors: GuardDescriptor[]): void {\n\t\tfor (const descriptor of descriptors) {\n\t\t\tconst { modulePath, exportKey, name } = descriptor;\n\n\t\t\tif (exportKey !== undefined) {\n\t\t\t\t// Cherry-picked: one lazy wrapper, resolves to exactly one guard\n\t\t\t\tconst lazyGuard = (context: GuardContext): GuardResult | PromiseLike<GuardResult> => {\n\t\t\t\t\tconst cached = sap.ui.require(modulePath) as unknown;\n\t\t\t\t\tif (cached !== undefined) {\n\t\t\t\t\t\tconst exports = resolveModuleExports(cached, modulePath, name, exportKey);\n\t\t\t\t\t\tif (exports.length === 0) return true;\n\t\t\t\t\t\treturn exports[0].fn(context);\n\t\t\t\t\t}\n\t\t\t\t\treturn new Promise<GuardResult>((resolve, reject) => {\n\t\t\t\t\t\tsap.ui.require(\n\t\t\t\t\t\t\t[modulePath],\n\t\t\t\t\t\t\t(mod: unknown) => {\n\t\t\t\t\t\t\t\tconst exports = resolveModuleExports(mod, modulePath, name, exportKey);\n\t\t\t\t\t\t\t\tif (exports.length === 0) {\n\t\t\t\t\t\t\t\t\tresolve(true);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresolve(exports[0].fn(context));\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t(err: Error) => {\n\t\t\t\t\t\t\t\tLog.warning(\n\t\t\t\t\t\t\t\t\t`guardRouter.guards: lazy load of \"${modulePath}\" failed`,\n\t\t\t\t\t\t\t\t\tString(err),\n\t\t\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treject(err);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t\tthis._registerGuardFromDescriptor(descriptor, lazyGuard);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Bare-path: try sync expansion from cache (preload likely finished)\n\t\t\tconst cached = sap.ui.require(modulePath) as unknown;\n\t\t\tif (cached !== undefined) {\n\t\t\t\tconst exports = resolveModuleExports(cached, modulePath, name);\n\t\t\t\tfor (const exp of exports) {\n\t\t\t\t\tthis._registerGuardFromDescriptor(descriptor, exp.fn);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Cache miss: register an expander that loads, expands once, and runs guard[0].\n\t\t\t// NOTE: Guards 1..N are appended to the guard array on first invocation,\n\t\t\t// which means they execute AFTER any imperative guards registered between\n\t\t\t// initialize() and first navigation. This differs from block mode where\n\t\t\t// all guards occupy contiguous positions. In practice this is rare because\n\t\t\t// the preload hint fires in the constructor and modules are typically cached\n\t\t\t// by the time initialize() runs.\n\t\t\tlet expanded = false;\n\t\t\tconst lazyExpander = (context: GuardContext): PromiseLike<GuardResult> => {\n\t\t\t\treturn new Promise<GuardResult>((resolve, reject) => {\n\t\t\t\t\tsap.ui.require(\n\t\t\t\t\t\t[modulePath],\n\t\t\t\t\t\t(mod: unknown) => {\n\t\t\t\t\t\t\tconst exports = resolveModuleExports(mod, modulePath, name);\n\t\t\t\t\t\t\tif (exports.length === 0) {\n\t\t\t\t\t\t\t\tresolve(true);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!expanded) {\n\t\t\t\t\t\t\t\texpanded = true;\n\t\t\t\t\t\t\t\tfor (let i = 1; i < exports.length; i++) {\n\t\t\t\t\t\t\t\t\tthis._registerGuardFromDescriptor(descriptor, exports[i].fn);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresolve(exports[0].fn(context));\n\t\t\t\t\t\t},\n\t\t\t\t\t\t(err: Error) => {\n\t\t\t\t\t\t\tLog.warning(\n\t\t\t\t\t\t\t\t`guardRouter.guards: lazy load of \"${modulePath}\" failed`,\n\t\t\t\t\t\t\t\tString(err),\n\t\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treject(err);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t};\n\t\t\tthis._registerGuardFromDescriptor(descriptor, lazyExpander);\n\t\t}\n\t}\n\n\t/**\n\t * Clean up guards on destroy. Bumps generation to discard pending async results.\n\t *\n\t * @since 1.0.1\n\t */\n\toverride destroy(): this {\n\t\tthis._destroyed = true;\n\t\tthis._pipeline.clear();\n\t\tthis._pendingGuardDescriptors = [];\n\t\tthis._sourceDescriptors = [];\n\t\tthis._cancelPendingNavigation();\n\t\tthis._suppressedHash = null;\n\t\tthis._lastSettlement = null;\n\t\tthis._manifestMeta.clear();\n\t\tthis._runtimeMeta.clear();\n\t\tthis._resolvedMetaCache.clear();\n\t\tsuper.destroy();\n\t\treturn this;\n\t}\n}\n"],"mappings":"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","ignoreList":[],"sourceRoot":""}},{"offset":{"line":4,"column":0},"map":{"version":3,"names":["NavigationOutcome","_interopRequireDefault","__NavigationOutcome","library","Lib","init","apiVersion","name","version","dependencies","types","interfaces","controls","elements","noLibraryCSS","DataType","registerEnum"],"sources":["library.ts"],"sourcesContent":["import Lib from \"sap/ui/core/Lib\";\nimport DataType from \"sap/ui/base/DataType\";\nimport \"sap/ui/core/library\";\nimport \"sap/m/library\";\nimport NavigationOutcome from \"./NavigationOutcome\";\n\nconst library = Lib.init({\n\tapiVersion: 2,\n\tname: \"ui5.guard.router\",\n\tversion: \"1.6.0\",\n\tdependencies: [\"sap.ui.core\", \"sap.m\"],\n\ttypes: [\"ui5.guard.router.NavigationOutcome\"],\n\tinterfaces: [],\n\tcontrols: [],\n\telements: [],\n\tnoLibraryCSS: true,\n});\n\nDataType.registerEnum(\"ui5.guard.router.NavigationOutcome\", NavigationOutcome);\n\nexport default library;\n"],"mappings":"AAAA,4QAIOA,EAAiBC,EAAAC,GAExB,MAAMC,EAAUC,EAAIC,KAAK,CACxBC,WAAY,EACZC,KAAM,mBACNC,QAAS,QACTC,aAAc,CAAC,cAAe,SAC9BC,MAAO,CAAC,sCACRC,WAAY,GACZC,SAAU,GACVC,SAAU,GACVC,aAAc,OAGfC,EAASC,aAAa,qCAAsChB,GAAmB,OAEhEG,CAAO","ignoreList":[],"sourceRoot":""}},{"offset":{"line":5,"column":0},"map":{"version":3,"names":[],"sources":["library-preload.js?bundle-code-0"],"mappings":"AAAA;AACA","sourcesContent":["sap.ui.require.preload({\n"],"sourceRoot":""}},{"offset":{"line":8,"column":0},"map":{"version":3,"file":"types.js","names":[],"sources":[],"mappings":"","ignoreList":[],"sourceRoot":""}}]}
1
+ {"version":3,"file":"library-preload.js","sections":[{"offset":{"line":1,"column":0},"map":{"version":3,"names":["LOG_COMPONENT","isGuardRedirect","value","route","length","isPromiseLike","then","GuardPipeline","_globalGuards","_enterGuards","Map","_leaveGuards","addGlobalGuard","guard","this","push","removeGlobalGuard","index","indexOf","splice","addEnterGuard","_addToGuardMap","removeEnterGuard","_removeFromGuardMap","addLeaveGuard","removeLeaveGuard","clear","evaluate","context","options","hasLeaveGuards","skipLeaveGuards","fromRoute","has","hasEnterGuards","toRoute","action","processEnterResult","enterResult","r","target","catch","error","runEnterPhase","_runEnterGuards","leaveResult","_runLeaveGuards","allowed","signal","aborted","map","key","guards","get","set","delete","registered","slice","i","result","_continueGuardsAsync","candidate","_validateLeaveGuardResult","Log","Error","String","globalResult","_runGuards","_runRouteGuards","_validateGuardResult","pendingResult","currentIndex","onBlock","label","isLeaveGuard","guardIndex","nextResult","warning"],"sources":["GuardPipeline.ts"],"sourcesContent":["import Log from \"sap/base/Log\";\nimport type { GuardFn, GuardContext, GuardResult, GuardRedirect } from \"./types\";\n\nconst LOG_COMPONENT = \"ui5.guard.router.Router\";\n\nfunction isGuardRedirect(value: unknown): value is GuardRedirect {\n\tif (typeof value !== \"object\" || value === null) {\n\t\treturn false;\n\t}\n\n\tconst { route } = value as GuardRedirect;\n\treturn typeof route === \"string\" && route.length > 0;\n}\n\n/**\n * Promises/A+ thenable detection via duck typing.\n *\n * We intentionally do not use `instanceof Promise` because that misses\n * cross-realm Promises and PromiseLike/thenable objects.\n */\nexport function isPromiseLike<T>(value: unknown): value is PromiseLike<T> {\n\tif ((typeof value !== \"object\" && typeof value !== \"function\") || value === null) {\n\t\treturn false;\n\t}\n\n\treturn typeof (value as PromiseLike<T>).then === \"function\";\n}\n\n/**\n * Normalized result of the guard decision pipeline.\n */\nexport type GuardDecision =\n\t| { action: \"allow\" }\n\t| { action: \"block\" }\n\t| { action: \"redirect\"; target: string | GuardRedirect }\n\t| { action: \"error\"; error: unknown };\n\n/**\n * Standalone guard evaluation pipeline.\n *\n * Owns guard storage (global, enter, leave) and runs the full\n * leave -> global-enter -> route-enter pipeline. Pure logic with\n * no dependency on Router state beyond the current route name\n * passed into evaluate().\n *\n * @namespace ui5.guard.router\n */\nexport default class GuardPipeline {\n\tprivate _globalGuards: GuardFn[] = [];\n\tprivate _enterGuards = new Map<string, GuardFn[]>();\n\tprivate _leaveGuards = new Map<string, GuardFn[]>();\n\n\t/** Register a guard that runs for every navigation. */\n\taddGlobalGuard(guard: GuardFn): void {\n\t\tthis._globalGuards.push(guard);\n\t}\n\n\t/** Remove a previously registered global guard by reference. */\n\tremoveGlobalGuard(guard: GuardFn): void {\n\t\tconst index = this._globalGuards.indexOf(guard);\n\t\tif (index !== -1) {\n\t\t\tthis._globalGuards.splice(index, 1);\n\t\t}\n\t}\n\n\t/**\n\t * Register an enter guard for a specific route.\n\t *\n\t * @param route - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function to register.\n\t */\n\taddEnterGuard(route: string, guard: GuardFn): void {\n\t\tthis._addToGuardMap(this._enterGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove a previously registered enter guard by reference.\n\t *\n\t * @param route - Route name.\n\t * @param guard - Guard function to remove.\n\t */\n\tremoveEnterGuard(route: string, guard: GuardFn): void {\n\t\tthis._removeFromGuardMap(this._enterGuards, route, guard);\n\t}\n\n\t/**\n\t * Register a leave guard for a specific route.\n\t *\n\t * Accepts `GuardFn` to support manifest-declared guards loaded from\n\t * untyped modules. Non-boolean return values are caught at runtime\n\t * by {@link _validateLeaveGuardResult}.\n\t *\n\t * @param route - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function to register as a leave guard.\n\t */\n\taddLeaveGuard(route: string, guard: GuardFn): void {\n\t\tthis._addToGuardMap(this._leaveGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove a previously registered leave guard by reference.\n\t *\n\t * @param route - Route name.\n\t * @param guard - Guard function to remove.\n\t */\n\tremoveLeaveGuard(route: string, guard: GuardFn): void {\n\t\tthis._removeFromGuardMap(this._leaveGuards, route, guard);\n\t}\n\n\t/**\n\t * Remove all registered guards.\n\t */\n\tclear(): void {\n\t\tthis._globalGuards = [];\n\t\tthis._enterGuards.clear();\n\t\tthis._leaveGuards.clear();\n\t}\n\n\t/**\n\t * Run the full guard pipeline (leave -> global enter -> route enter) and\n\t * return a normalized decision. Stays synchronous when all guards return\n\t * plain values; returns a Promise only when an async guard is encountered.\n\t *\n\t * @param context - Complete guard context including AbortSignal.\n\t * `context.fromRoute` controls leave-guard lookup: empty string skips leave guards.\n\t * @param options - Optional evaluation options.\n\t * @param options.skipLeaveGuards - When true, leave guards are skipped even if\n\t * `context.fromRoute` is set. Used by redirect chain hops to avoid re-running\n\t * leave guards while still preserving `fromRoute` in the context.\n\t * @returns A synchronous {@link GuardDecision} when all guards return plain values,\n\t * or a `Promise<GuardDecision>` when at least one guard returns a thenable.\n\t */\n\tevaluate(context: GuardContext, options?: { skipLeaveGuards?: boolean }): GuardDecision | Promise<GuardDecision> {\n\t\tconst hasLeaveGuards =\n\t\t\t!options?.skipLeaveGuards && context.fromRoute !== \"\" && this._leaveGuards.has(context.fromRoute);\n\t\tconst hasEnterGuards =\n\t\t\tthis._globalGuards.length > 0 || (context.toRoute !== \"\" && this._enterGuards.has(context.toRoute));\n\n\t\tif (!hasLeaveGuards && !hasEnterGuards) {\n\t\t\treturn { action: \"allow\" };\n\t\t}\n\n\t\tconst processEnterResult = (\n\t\t\tenterResult: GuardResult | Promise<GuardResult>,\n\t\t): GuardDecision | Promise<GuardDecision> => {\n\t\t\tif (isPromiseLike(enterResult)) {\n\t\t\t\treturn enterResult\n\t\t\t\t\t.then((r: GuardResult): GuardDecision => {\n\t\t\t\t\t\tif (r === true) return { action: \"allow\" };\n\t\t\t\t\t\tif (r === false) return { action: \"block\" };\n\t\t\t\t\t\treturn { action: \"redirect\", target: r };\n\t\t\t\t\t})\n\t\t\t\t\t.catch((error: unknown): GuardDecision => {\n\t\t\t\t\t\treturn { action: \"error\", error };\n\t\t\t\t\t});\n\t\t\t}\n\t\t\tif (enterResult === true) return { action: \"allow\" };\n\t\t\tif (enterResult === false) return { action: \"block\" };\n\t\t\treturn { action: \"redirect\", target: enterResult };\n\t\t};\n\n\t\tconst runEnterPhase = (): GuardDecision | Promise<GuardDecision> => {\n\t\t\tconst enterResult = this._runEnterGuards(context.toRoute, context);\n\t\t\treturn processEnterResult(enterResult);\n\t\t};\n\n\t\ttry {\n\t\t\tif (hasLeaveGuards) {\n\t\t\t\tconst leaveResult = this._runLeaveGuards(context);\n\n\t\t\t\tif (isPromiseLike(leaveResult)) {\n\t\t\t\t\treturn leaveResult\n\t\t\t\t\t\t.then((allowed: boolean): GuardDecision | Promise<GuardDecision> => {\n\t\t\t\t\t\t\tif (allowed !== true) return { action: \"block\" };\n\t\t\t\t\t\t\tif (context.signal.aborted) return { action: \"block\" };\n\t\t\t\t\t\t\treturn runEnterPhase();\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch((error: unknown): GuardDecision => {\n\t\t\t\t\t\t\treturn { action: \"error\", error };\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (leaveResult !== true) return { action: \"block\" };\n\t\t\t}\n\n\t\t\treturn runEnterPhase();\n\t\t} catch (error) {\n\t\t\treturn { action: \"error\", error };\n\t\t}\n\t}\n\n\tprivate _addToGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\t\tlet guards = map.get(key);\n\t\tif (!guards) {\n\t\t\tguards = [];\n\t\t\tmap.set(key, guards);\n\t\t}\n\t\tguards.push(guard);\n\t}\n\n\tprivate _removeFromGuardMap<T>(map: Map<string, T[]>, key: string, guard: T): void {\n\t\tconst guards = map.get(key);\n\t\tif (!guards) return;\n\t\tconst index = guards.indexOf(guard);\n\t\tif (index !== -1) guards.splice(index, 1);\n\t\tif (guards.length === 0) map.delete(key);\n\t}\n\n\t/**\n\t * Run leave guards for the current route. Returns boolean (no redirects).\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runLeaveGuards(context: GuardContext): boolean | Promise<boolean> {\n\t\tconst registered = this._leaveGuards.get(context.fromRoute);\n\t\tif (!registered || registered.length === 0) return true;\n\n\t\tconst guards = registered.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateLeaveGuardResult(candidate),\n\t\t\t\t\t\t\"Leave guard\",\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t) as Promise<boolean>;\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateLeaveGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Leave guard [${i}] on route \"${context.fromRoute}\" threw, navigation failed`,\n\t\t\t\t\terror instanceof Error ? error : String(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** Run global guards, then route-specific guards. Stays sync when possible. */\n\tprivate _runEnterGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tconst globalResult = this._runGuards(this._globalGuards, context);\n\n\t\tif (isPromiseLike(globalResult)) {\n\t\t\treturn globalResult.then((result: GuardResult) => {\n\t\t\t\tif (result !== true) return result;\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\treturn this._runRouteGuards(toRoute, context);\n\t\t\t});\n\t\t}\n\t\tif (globalResult !== true) return globalResult;\n\t\treturn this._runRouteGuards(toRoute, context);\n\t}\n\n\t/** Run route-specific guards if any are registered. */\n\tprivate _runRouteGuards(toRoute: string, context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tif (!toRoute || !this._enterGuards.has(toRoute)) return true;\n\t\treturn this._runGuards(this._enterGuards.get(toRoute)!, context);\n\t}\n\n\t/**\n\t * Run guards sync; switch to async path if a Promise is returned.\n\t *\n\t * The guard array is snapshot-copied before iteration so that guards\n\t * may safely add/remove themselves (e.g. one-shot guards) without\n\t * affecting the current pipeline run.\n\t */\n\tprivate _runGuards(guards: GuardFn[], context: GuardContext): GuardResult | Promise<GuardResult> {\n\t\tguards = guards.slice();\n\t\tfor (let i = 0; i < guards.length; i++) {\n\t\t\ttry {\n\t\t\t\tconst result = guards[i](context);\n\t\t\t\tif (isPromiseLike(result)) {\n\t\t\t\t\treturn this._continueGuardsAsync(\n\t\t\t\t\t\tresult,\n\t\t\t\t\t\tguards,\n\t\t\t\t\t\ti,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t(candidate) => this._validateGuardResult(candidate),\n\t\t\t\t\t\t\"Enter guard\",\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (result !== true) return this._validateGuardResult(result);\n\t\t\t} catch (error) {\n\t\t\t\tLog.error(\n\t\t\t\t\t`Enter guard [${i}] on route \"${context.toRoute}\" threw, navigation failed`,\n\t\t\t\t\terror instanceof Error ? error : String(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Continue guard array async from the first Promise onward.\n\t *\n\t * Shared by both enter and leave guard pipelines. The `onBlock` callback\n\t * determines what to return for non-true results: leave guards always\n\t * return `false`, enter guards validate and may return redirects.\n\t *\n\t * @param isLeaveGuard - When true, error logs reference `fromRoute`; otherwise `toRoute`.\n\t */\n\tprivate async _continueGuardsAsync(\n\t\tpendingResult: PromiseLike<GuardResult>,\n\t\tguards: GuardFn[],\n\t\tcurrentIndex: number,\n\t\tcontext: GuardContext,\n\t\tonBlock: (result: unknown) => GuardResult,\n\t\tlabel: string,\n\t\tisLeaveGuard: boolean,\n\t): Promise<GuardResult> {\n\t\tlet guardIndex = currentIndex;\n\t\ttry {\n\t\t\tconst result = await pendingResult;\n\t\t\tif (result !== true) return onBlock(result);\n\n\t\t\tfor (let i = currentIndex + 1; i < guards.length; i++) {\n\t\t\t\tif (context.signal.aborted) return false;\n\t\t\t\tguardIndex = i;\n\t\t\t\tconst nextResult = await guards[i](context);\n\t\t\t\tif (nextResult !== true) return onBlock(nextResult);\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (!context.signal.aborted) {\n\t\t\t\tconst route = isLeaveGuard ? context.fromRoute : context.toRoute;\n\t\t\t\tLog.error(\n\t\t\t\t\t`${label} [${guardIndex}] on route \"${route}\" threw, navigation failed`,\n\t\t\t\t\terror instanceof Error ? error : String(error),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/** Validate a non-true guard result; invalid values become false. */\n\tprivate _validateGuardResult(result: unknown): GuardResult {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tif (typeof result === \"string\" && result.length > 0) return result;\n\t\tif (isGuardRedirect(result)) return result;\n\t\tLog.warning(\"Guard returned invalid value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n\n\t/** Validate a leave guard result; non-boolean values log a warning and block. */\n\tprivate _validateLeaveGuardResult(result: unknown): boolean {\n\t\tif (typeof result === \"boolean\") return result;\n\t\tLog.warning(\"Leave guard returned non-boolean value, treating as block\", String(result), LOG_COMPONENT);\n\t\treturn false;\n\t}\n}\n"],"mappings":"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","ignoreList":[],"sourceRoot":""}},{"offset":{"line":2,"column":0},"map":{"version":3,"names":["NavigationOutcome","Object","freeze","Committed","Bypassed","Blocked","Redirected","Cancelled","Error"],"sources":["NavigationOutcome.ts"],"sourcesContent":["/**\n * Outcome of a navigation after the guard pipeline settles.\n *\n * Registered as a UI5 enum via `library.ts` so that it is discoverable\n * through `sap.ui.base.DataType.getType()`. Application code can import\n * the value object directly.\n *\n * @enum {string}\n * @namespace ui5.guard.router\n * @since 1.2.0\n */\nconst NavigationOutcome = Object.freeze({\n\t/** Navigation was allowed and the target route activated. @since 1.2.0 */\n\tCommitted: \"committed\",\n\t/** Navigation was allowed, but no route matched; UI5 continued with bypassed handling. @since 1.3.0 */\n\tBypassed: \"bypassed\",\n\t/** A guard blocked navigation; the previous route remains active. @since 1.2.0 */\n\tBlocked: \"blocked\",\n\t/** A guard redirected navigation to a different route. @since 1.2.0 */\n\tRedirected: \"redirected\",\n\t/** Navigation was cancelled before settling (superseded, stopped, or destroyed). @since 1.2.0 */\n\tCancelled: \"cancelled\",\n\t/** A guard threw or rejected; the previous route remains active. @since 1.4.0 */\n\tError: \"error\",\n});\n\ntype NavigationOutcome = (typeof NavigationOutcome)[keyof typeof NavigationOutcome];\n\nexport default NavigationOutcome;\n"],"mappings":"AAAA,kFAWA,MAAMA,EAAoBC,OAAOC,OAAO,CAEvCC,UAAW,YAEXC,SAAU,WAEVC,QAAS,UAETC,WAAY,aAEZC,UAAW,YAEXC,MAAO,UACL,OAIYR,CAAiB","ignoreList":[],"sourceRoot":""}},{"offset":{"line":3,"column":0},"map":{"version":3,"names":["NavigationOutcome","_interopRequireDefault","__NavigationOutcome","GuardPipeline","__GuardPipeline","isPromiseLike","HistoryDirection","coreLibrary","routing","LOG_COMPONENT","isRouteGuardConfig","guard","IDLE","kind","isRecord","value","Array","isArray","proto","Object","getPrototypeOf","prototype","isOneOf","values","set","Set","v","has","isUnknownRouteRegistrationPolicy","isNavToPreflightMode","isGuardLoading","isInheritance","OPTIONAL_OR_REST_SEGMENT","stripInlineQuery","seg","mqIdx","indexOf","slice","oqIdx","patternSegments","pattern","split","map","filter","test","isPatternAncestor","ancestorPattern","candidatePattern","ancestorSegments","length","candidateSegments","every","i","candidateSeg","startsWith","resolveGuardModulePath","dotPath","componentNamespace","replace","fullDotPath","parseGuardEntry","entry","hashIndex","rawPath","exportKey","undefined","modulePath","lastSegment","pop","name","guardWarning","detail","Log","warning","resolveModuleExports","moduleExport","descriptorName","moduleName","debug","fn","index","parseInt","Number","isNaN","results","push","entries","resolvedName","key","val","parseGuardDescriptors","guards","JSON","stringify","descriptors","pushEntries","route","type","label","parsed","config","leave","enter","info","DEFAULT_OPTIONS","unknownRouteRegistration","navToPreflight","guardLoading","inheritance","applyOption","raw","target","normalizeGuardRouterOptions","result","MAX_REDIRECT_DEPTH","Router","MobileRouter","extend","constructor","_constructor","args","routes","owner","rest","rawConfig","isRecordConfig","guardRouter","cleanConfig","MobileRouter.prototype.constructor.apply","this","_options","_pipeline","_currentRoute","_currentHash","_phase","_parseGeneration","_suppressedHash","_settlementResolvers","_lastSettlement","_pendingGuardDescriptors","_sourceDescriptors","_destroyed","_manifestMeta","Map","_runtimeMeta","_resolvedMetaCache","_routeNames","r","keys","routeMeta","routeName","meta","freeze","appConfig","getManifestEntry","id","uniquePaths","d","sap","ui","require","initialize","_initialize","MobileRouter.prototype.initialize.call","expandedDescriptors","_expandGuardDescriptors","_registerLazyGuards","_loadAndRegisterGuards","then","catch","err","error","String","addRoute","_addRoute","oConfig","MobileRouter.prototype.addRoute.apply","includes","clear","getRoute","newPattern","getPattern","newDescriptors","_expandGuardDescriptorsForNewRoute","newName","descriptor","ancestorRoute","_collectRoutePatterns","toSorted","a","b","pa","pb","addGuard","_addGuard","_isFn","addGlobalGuard","removeGuard","_removeGuard","removeGlobalGuard","addRouteGuard","_addRouteGuard","_handleUnknownRouteRegistration","hasHandler","beforeEnter","addEnterGuard","beforeLeave","addLeaveGuard","removeRouteGuard","_removeRouteGuard","removeLeaveGuard","removeEnterGuard","_addLeaveGuard","_resolveNavToArgs","componentTargetInfoOrReplace","replaceOrOptions","options","guardOptions","componentTargetInfo","method","methodName","Error","_removeLeaveGuard","getRouteMeta","_getRouteMeta","_EMPTY_META","cached","get","_resolveInheritedMeta","_resolveFlatMeta","setRouteMeta","_setRouteMeta","navigationSettled","_navigationSettled","Promise","resolve","status","Committed","hash","attachNavigationSettled","_attachNavigationSettled","oData","fnFunction","oListener","attachEvent","detachNavigationSettled","_detachNavigationSettled","detachEvent","_flushSettlement","resolvers","fireEvent","navTo","_navTo","parameters","origin","MobileRouter.prototype.navTo.call","_cancelPendingNavigation","targetHash","getURL","routeInfo","getRouteInfoByHash","toRoute","attempt","skipGuards","_commitNavigation","controller","AbortController","generation","context","_createGuardContext","signal","decision","evaluate","_applyPreflightDecision","bag","_errorNavigation","bReplace","action","_blockNavigation","_startRedirectChain","parse","_parse","newHash","_applyDecision","stop","_stop","MobileRouter.prototype.stop.call","abort","Cancelled","wasRedirect","Redirected","Bypassed","MobileRouter.prototype.parse.call","_redirect","chain","targetName","targetParameters","targetRoute","visited","join","attemptedHash","restoreHash","size","add","settlementBefore","resolvedHash","toHash","toArguments","arguments","fromRoute","fromHash","toMeta","fromMeta","skipLeaveGuards","_applyRedirectDecision","redirectsToCurrentHash","Blocked","_restoreHashIfNeeded","_restoreHash","suppressParse","hashChanger","getHashChanger","replaceHash","Unknown","allRoutes","patternByName","expanded","sort","manifest","runtime","routeEntry","find","ancestors","merged","ancestor","ancestorManifest","assign","ancestorRuntime","ownManifest","ownRuntime","promises","all","exports","_registerGuardFromDescriptor","guardFn","lazyGuard","reject","mod","exp","lazyExpander","destroy","_destroy","MobileRouter.prototype.destroy.call"],"sources":["Router.ts"],"sourcesContent":["import MobileRouter from \"sap/m/routing/Router\";\nimport Log from \"sap/base/Log\";\nimport coreLibrary from \"sap/ui/core/library\";\nimport type { ComponentTargetParameters } from \"sap/ui/core/routing/Router\";\nimport type { $RouteSettings } from \"sap/ui/core/routing/Route\";\nimport type {\n\tGuardFn,\n\tGuardContext,\n\tGuardNavToOptions,\n\tGuardResult,\n\tGuardRedirect,\n\tGuardRouter,\n\tGuardLoading,\n\tInheritance,\n\tLeaveGuardFn,\n\tManifestRouteGuardConfig,\n\tNavToPreflightMode,\n\tNavigationResult,\n\tRouter$NavigationSettledEvent,\n\tRouteGuardConfig,\n\tUnknownRouteRegistrationPolicy,\n} from \"./types\";\nimport NavigationOutcome from \"./NavigationOutcome\";\nimport GuardPipeline, { type GuardDecision, isPromiseLike } from \"./GuardPipeline\";\n\nconst HistoryDirection = coreLibrary.routing.HistoryDirection;\n\nconst LOG_COMPONENT = \"ui5.guard.router.Router\";\n\nfunction isRouteGuardConfig(guard: GuardFn | RouteGuardConfig): guard is RouteGuardConfig {\n\treturn typeof guard === \"object\" && guard !== null;\n}\n\n/** Snapshot of an in-flight navigation being evaluated by the guard pipeline. */\ninterface NavigationAttempt {\n\treadonly hash: string;\n\treadonly route: string;\n\treadonly controller: AbortController;\n\treadonly generation: number;\n}\n\ninterface PhaseIdle {\n\treadonly kind: \"idle\";\n}\n\ninterface PhaseEvaluating {\n\treadonly kind: \"evaluating\";\n\treadonly attempt: NavigationAttempt;\n}\n\ninterface PhaseCommitting {\n\treadonly kind: \"committing\";\n\treadonly hash: string;\n\treadonly route: string;\n\treadonly origin: \"preflight\" | \"redirect\" | \"parse\";\n}\n\ntype RouterPhase = PhaseIdle | PhaseEvaluating | PhaseCommitting;\n\nconst IDLE: PhaseIdle = { kind: \"idle\" };\n\n/** Type guard for plain objects. */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n\tconst proto = Object.getPrototypeOf(value);\n\treturn proto === Object.prototype || proto === null;\n}\n\n/** Create a type-narrowing validator for a finite set of string literal values. */\nfunction isOneOf<T extends string>(...values: T[]): (v: unknown) => v is T {\n\tconst set: ReadonlySet<string> = new Set(values);\n\treturn (v: unknown): v is T => typeof v === \"string\" && set.has(v);\n}\n\nconst isUnknownRouteRegistrationPolicy = isOneOf<UnknownRouteRegistrationPolicy>(\"ignore\", \"warn\", \"throw\");\nconst isNavToPreflightMode = isOneOf<NavToPreflightMode>(\"guard\", \"bypass\", \"off\");\nconst isGuardLoading = isOneOf<GuardLoading>(\"block\", \"lazy\");\nconst isInheritance = isOneOf<Inheritance>(\"none\", \"pattern-tree\");\n\n/** Matches a standalone optional (`:param:`) or rest (`:param*:`) segment. */\nconst OPTIONAL_OR_REST_SEGMENT = /^:[^:]*\\*?:$/;\n\n/**\n * Strips inline query and optional-query suffixes from a segment.\n *\n * UI5 (crossroads.js) allows query parameters to attach directly to a\n * path segment without a `/` separator:\n * - `product{?query}` → mandatory query on `product`\n * - `product:?query:` → optional query on `product`\n * - `{id}{?query}` → mandatory param + mandatory query\n *\n * For pattern-tree ancestry we only care about the path portion,\n * so these suffixes are stripped.\n */\nfunction stripInlineQuery(seg: string): string {\n\t// Strip mandatory query `{?...}` suffix\n\tconst mqIdx = seg.indexOf(\"{?\");\n\tif (mqIdx !== -1) return seg.slice(0, mqIdx);\n\t// Strip optional query `:?...:` suffix\n\tconst oqIdx = seg.indexOf(\":?\");\n\tif (oqIdx !== -1) return seg.slice(0, oqIdx);\n\treturn seg;\n}\n\n/**\n * Extract mandatory path segments from a UI5 route pattern.\n *\n * Splits on `/`, strips inline query suffixes, then drops empty segments,\n * standalone optional (`:param:`), and rest (`:param*:`) segments.\n */\nfunction patternSegments(pattern: string): string[] {\n\treturn pattern\n\t\t.split(\"/\")\n\t\t.map(stripInlineQuery)\n\t\t.filter((seg) => seg !== \"\" && !OPTIONAL_OR_REST_SEGMENT.test(seg));\n}\n\n/**\n * Check if `ancestorPattern` is a URL-tree ancestor of `candidatePattern`.\n *\n * Both patterns are reduced to their mandatory path segments and compared\n * positionally. Mandatory parameter segments (`{paramA}`, `{paramB}`) are\n * treated as equivalent regardless of name, so `employees/{empId}` is\n * recognized as an ancestor of `employees/{id}/resume`.\n */\nfunction isPatternAncestor(ancestorPattern: string, candidatePattern: string): boolean {\n\tif (ancestorPattern === \"\") return true;\n\tconst ancestorSegments = patternSegments(ancestorPattern);\n\tif (ancestorSegments.length === 0) return false;\n\tconst candidateSegments = patternSegments(candidatePattern);\n\tif (candidateSegments.length <= ancestorSegments.length) return false;\n\treturn ancestorSegments.every((seg, i) => {\n\t\tconst candidateSeg = candidateSegments[i];\n\t\tif (seg === candidateSeg) return true;\n\t\t// Treat any two mandatory parameter segments as equivalent\n\t\treturn seg.startsWith(\"{\") && candidateSeg.startsWith(\"{\");\n\t});\n}\n\n/** Parsed guard declaration from the manifest `guards` block. */\ninterface GuardDescriptor {\n\treadonly route: string; // \"*\" for global, route name for per-route\n\treadonly type: \"enter\" | \"leave\";\n\treadonly modulePath: string;\n\treadonly name: string;\n\treadonly exportKey?: string;\n}\n\n/**\n * Resolve a dot-notation module path following UI5 routing conventions.\n * Mirrors `sap.ui.core.routing.Target._getEffectiveObjectName()`.\n *\n * - Paths prefixed with `\"module:\"` are treated as absolute (the prefix is\n * stripped and dots become slashes).\n * - All other paths are prefixed with the component namespace.\n */\nfunction resolveGuardModulePath(dotPath: string, componentNamespace: string): string {\n\tif (dotPath.startsWith(\"module:\")) {\n\t\treturn dotPath.slice(\"module:\".length).replace(/\\./g, \"/\");\n\t}\n\tconst fullDotPath = componentNamespace ? componentNamespace + \".\" + dotPath : dotPath;\n\treturn fullDotPath.replace(/\\./g, \"/\");\n}\n\n/**\n * Split a manifest guard entry on the first `#` to separate the module path\n * from an optional export key, then derive a human-readable guard name.\n */\nfunction parseGuardEntry(\n\tentry: string,\n\tcomponentNamespace: string,\n): { modulePath: string; name: string; exportKey?: string } {\n\tconst hashIndex = entry.indexOf(\"#\");\n\tconst rawPath = hashIndex === -1 ? entry : entry.slice(0, hashIndex);\n\tconst exportKey = hashIndex === -1 ? undefined : entry.slice(hashIndex + 1);\n\n\tconst modulePath = resolveGuardModulePath(rawPath, componentNamespace);\n\n\t// Name: export key if present, otherwise last segment of the dot path\n\tconst lastSegment = rawPath.split(\".\").pop() ?? rawPath;\n\tconst name = exportKey ?? lastSegment;\n\n\treturn { modulePath, name, exportKey };\n}\n\ninterface ResolvedGuardExport {\n\treadonly name: string;\n\treadonly fn: GuardFn;\n}\n\n/** Log a warning about a guard module entry in the manifest. */\nfunction guardWarning(modulePath: string, detail: string): void {\n\tLog.warning(`guardRouter.guards: \"${modulePath}\" ${detail}`, undefined, LOG_COMPONENT);\n}\n\n/**\n * Detect the export shape of a loaded guard module and extract guard functions.\n *\n * Shapes:\n * - function → single guard\n * - Array → ordered guards (non-functions warned and skipped)\n * - plain object → named guards in key order (non-functions warned and skipped)\n *\n * When `exportKey` is set, only the matching export is returned.\n * When `exportKey` is set on a function export, the key is ignored with a debug warning.\n */\nfunction resolveModuleExports(\n\tmoduleExport: unknown,\n\tmodulePath: string,\n\tdescriptorName: string,\n\texportKey?: string,\n): ResolvedGuardExport[] {\n\tconst moduleName = modulePath.split(\"/\").pop() ?? modulePath;\n\n\t// Shape 1: function\n\tif (typeof moduleExport === \"function\") {\n\t\tif (exportKey !== undefined) {\n\t\t\tLog.debug(\n\t\t\t\t`guardRouter.guards: \"${modulePath}#${exportKey}\" is a single function, ignoring export key`,\n\t\t\t\tundefined,\n\t\t\t\tLOG_COMPONENT,\n\t\t\t);\n\t\t}\n\t\treturn [{ name: descriptorName, fn: moduleExport as GuardFn }];\n\t}\n\n\t// Shape 2: array\n\tif (Array.isArray(moduleExport)) {\n\t\tif (moduleExport.length === 0) {\n\t\t\tguardWarning(modulePath, \"exported an empty array, skipping\");\n\t\t\treturn [];\n\t\t}\n\n\t\tif (exportKey !== undefined) {\n\t\t\tconst index = parseInt(exportKey, 10);\n\t\t\tif (Number.isNaN(index) || index < 0 || index >= moduleExport.length) {\n\t\t\t\tguardWarning(modulePath, `#${exportKey} - index out of range, skipping`);\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tconst entry = moduleExport[index] as unknown;\n\t\t\tif (typeof entry !== \"function\") {\n\t\t\t\tguardWarning(modulePath, `#${exportKey} is not a function, skipping`);\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\treturn [{ name: `${moduleName}#${exportKey}`, fn: entry as GuardFn }];\n\t\t}\n\n\t\tconst results: ResolvedGuardExport[] = [];\n\t\tfor (let i = 0; i < moduleExport.length; i++) {\n\t\t\tconst entry = moduleExport[i] as unknown;\n\t\t\tif (typeof entry !== \"function\") {\n\t\t\t\tguardWarning(modulePath, `[${i}] is not a function, skipping`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresults.push({ name: `${moduleName}#${i}`, fn: entry as GuardFn });\n\t\t}\n\t\treturn results;\n\t}\n\n\t// Shape 3: plain object\n\tif (isRecord(moduleExport)) {\n\t\tconst entries = Object.entries(moduleExport);\n\t\tif (entries.length === 0) {\n\t\t\tguardWarning(modulePath, \"exported an empty object, skipping\");\n\t\t\treturn [];\n\t\t}\n\n\t\tif (exportKey !== undefined) {\n\t\t\tlet value: unknown = moduleExport[exportKey];\n\t\t\tlet resolvedName = exportKey;\n\t\t\tif (value === undefined) {\n\t\t\t\tconst index = parseInt(exportKey, 10);\n\t\t\t\tif (!Number.isNaN(index) && index >= 0 && index < entries.length) {\n\t\t\t\t\tconst [key, val] = entries[index];\n\t\t\t\t\tvalue = val;\n\t\t\t\t\tresolvedName = key;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (value === undefined) {\n\t\t\t\tguardWarning(modulePath, `#${exportKey} - key not found, skipping`);\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tif (typeof value !== \"function\") {\n\t\t\t\tguardWarning(modulePath, `#${exportKey} is not a function, skipping`);\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\treturn [{ name: resolvedName, fn: value as GuardFn }];\n\t\t}\n\n\t\tconst results: ResolvedGuardExport[] = [];\n\t\tfor (const [key, value] of entries) {\n\t\t\tif (typeof value !== \"function\") {\n\t\t\t\tguardWarning(modulePath, `.${key} is not a function, skipping`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresults.push({ name: key, fn: value as GuardFn });\n\t\t}\n\t\treturn results;\n\t}\n\n\tguardWarning(modulePath, \"did not export a function, array, or plain object, skipping\");\n\treturn [];\n}\n\n/**\n * Parse the `guards` block from the guardRouter config into an array of\n * {@link GuardDescriptor} objects.\n *\n * Handles:\n * - `\"*\"` key with `string[]` -> global enter guards\n * - Route name with `string[]` (shorthand) -> enter guards\n * - Route name with `{ enter: [...], leave: [...] }` -> enter + leave guards\n * - `\"*\"` with object form -> warn, treat enter as global\n * - `\"*\"` leave -> warn, skip (global leave guards not supported)\n * - Invalid entries -> warn, skip\n */\nfunction parseGuardDescriptors(guards: unknown, componentNamespace: string): GuardDescriptor[] {\n\tif (!isRecord(guards)) {\n\t\tLog.warning(\"guardRouter.guards is not a plain object, skipping\", JSON.stringify(guards), LOG_COMPONENT);\n\t\treturn [];\n\t}\n\n\tconst descriptors: GuardDescriptor[] = [];\n\n\tfunction pushEntries(entries: unknown[], route: string, type: \"enter\" | \"leave\", label: string): void {\n\t\tfor (const entry of entries) {\n\t\t\tif (typeof entry !== \"string\" || entry.length === 0) {\n\t\t\t\tLog.warning(\n\t\t\t\t\t`guardRouter.guards${label}: invalid entry, skipping`,\n\t\t\t\t\tJSON.stringify(entry),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst parsed = parseGuardEntry(entry, componentNamespace);\n\t\t\tdescriptors.push({ route, type, ...parsed });\n\t\t}\n\t}\n\n\tfor (const [key, value] of Object.entries(guards)) {\n\t\tif (Array.isArray(value)) {\n\t\t\tpushEntries(value, key, \"enter\", `[\"${key}\"]`);\n\t\t} else if (isRecord(value)) {\n\t\t\tconst config = value as ManifestRouteGuardConfig;\n\n\t\t\tif (key === \"*\" && config.leave !== undefined) {\n\t\t\t\tLog.warning(\n\t\t\t\t\t'guardRouter.guards[\"*\"].leave: global leave guards are not supported, skipping',\n\t\t\t\t\tundefined,\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (key === \"*\" && config.enter === undefined && config.leave !== undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (key === \"*\" && config.enter !== undefined) {\n\t\t\t\tLog.info('guardRouter.guards[\"*\"]: object form; treating enter as global', undefined, LOG_COMPONENT);\n\t\t\t}\n\n\t\t\tif (Array.isArray(config.enter)) {\n\t\t\t\tpushEntries(config.enter, key, \"enter\", `[\"${key}\"].enter`);\n\t\t\t}\n\n\t\t\tif (key !== \"*\" && Array.isArray(config.leave)) {\n\t\t\t\tpushEntries(config.leave, key, \"leave\", `[\"${key}\"].leave`);\n\t\t\t}\n\t\t} else {\n\t\t\tLog.warning(\n\t\t\t\t`guardRouter.guards[\"${key}\"]: expected string[] or { enter?, leave? }, skipping`,\n\t\t\t\tJSON.stringify(value),\n\t\t\t\tLOG_COMPONENT,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn descriptors;\n}\n\ninterface ResolvedGuardRouterOptions {\n\treadonly unknownRouteRegistration: UnknownRouteRegistrationPolicy;\n\treadonly navToPreflight: NavToPreflightMode;\n\treadonly guardLoading: GuardLoading;\n\treadonly inheritance: Inheritance;\n}\n\nconst DEFAULT_OPTIONS: ResolvedGuardRouterOptions = {\n\tunknownRouteRegistration: \"warn\",\n\tnavToPreflight: \"guard\",\n\tguardLoading: \"lazy\",\n\tinheritance: \"none\",\n};\n\nfunction applyOption<K extends keyof ResolvedGuardRouterOptions>(\n\traw: Record<string, unknown>,\n\tkey: K,\n\tguard: (v: unknown) => v is ResolvedGuardRouterOptions[K],\n\ttarget: { -readonly [P in keyof ResolvedGuardRouterOptions]: ResolvedGuardRouterOptions[P] },\n): void {\n\tif (raw[key] !== undefined) {\n\t\tif (guard(raw[key])) {\n\t\t\ttarget[key] = raw[key] as ResolvedGuardRouterOptions[K];\n\t\t} else {\n\t\t\tLog.warning(`guardRouter.${key} has invalid value, using default`, JSON.stringify(raw[key]), LOG_COMPONENT);\n\t\t}\n\t}\n}\n\nfunction normalizeGuardRouterOptions(raw: unknown): ResolvedGuardRouterOptions {\n\tif (!isRecord(raw)) {\n\t\tif (raw !== undefined) {\n\t\t\tLog.warning(\"guardRouter config is not a plain object, using defaults\", JSON.stringify(raw), LOG_COMPONENT);\n\t\t}\n\t\treturn DEFAULT_OPTIONS;\n\t}\n\n\tconst result = { ...DEFAULT_OPTIONS };\n\tapplyOption(raw, \"unknownRouteRegistration\", isUnknownRouteRegistrationPolicy, result);\n\tapplyOption(raw, \"navToPreflight\", isNavToPreflightMode, result);\n\tapplyOption(raw, \"guardLoading\", isGuardLoading, result);\n\tapplyOption(raw, \"inheritance\", isInheritance, result);\n\treturn result;\n}\n\n/** Maximum number of hops in a redirect chain before it is treated as a loop. */\nconst MAX_REDIRECT_DEPTH = 10;\n\n/** State threaded through a redirect chain. */\ninterface RedirectChainContext {\n\t/** Hashes whose guards have been evaluated in this chain (mutated via .add()). */\n\tvisited: Set<string>;\n\t/** Hash of the originally attempted navigation (for settlement / hash restore). */\n\treadonly attemptedHash: string | undefined;\n\t/** Whether to restore the hash on block (true for parse path, false for preflight). */\n\treadonly restoreHash: boolean;\n\t/** Original source route (the route the user occupies). */\n\treadonly fromRoute: string;\n\t/** Original source hash (the hash the user occupies). */\n\treadonly fromHash: string;\n\t/** Shared AbortSignal from the original navigation. */\n\treadonly signal: AbortSignal;\n\t/** Shared generation counter from the original navigation. */\n\treadonly generation: number;\n\t/** Shared bag from the original navigation's guard context. */\n\treadonly bag: Map<string, unknown>;\n}\n\n/**\n * Router with navigation guard support.\n *\n * Extends `sap.m.routing.Router` with a shared guard pipeline that\n * evaluates registered guard functions before route matching, target\n * loading, or event firing occurs.\n *\n * Two entry points feed the same pipeline:\n * - `navTo()` runs guards as a preflight check. Blocked or redirected\n * navigations never change the hash or push history entries.\n * - `parse()` runs guards as a fallback for browser back/forward, URL\n * bar entry, and direct hash changes where the hash has already changed\n * before guards can intercept.\n *\n * Key assumptions (see docs/reference/architecture.md for full rationale):\n * - `parse()` is intentionally NOT async. Sync guards execute in the\n * same tick; async guards fall back to a deferred path.\n * - `replaceHash` fires `hashChanged` synchronously (validated by test).\n * - `setHash` (via `super.navTo`) fires `hashChanged` synchronously (validated by test).\n * - Redirect targets are evaluated by the guard pipeline with loop detection.\n *\n * @namespace ui5.guard.router\n * @extends sap.m.routing.Router\n */\nexport default class Router extends MobileRouter implements GuardRouter {\n\tprivate _options: ResolvedGuardRouterOptions = DEFAULT_OPTIONS;\n\tprivate _pipeline = new GuardPipeline();\n\tprivate _currentRoute = \"\";\n\tprivate _currentHash: string | null = null;\n\tprivate _phase: RouterPhase = IDLE;\n\tprivate _parseGeneration = 0;\n\tprivate _suppressedHash: string | null = null;\n\tprivate _settlementResolvers: ((result: NavigationResult) => void)[] = [];\n\tprivate _lastSettlement: NavigationResult | null = null;\n\tprivate _pendingGuardDescriptors: GuardDescriptor[] = [];\n\tprivate _sourceDescriptors: GuardDescriptor[] = [];\n\tprivate _destroyed = false;\n\tprivate _manifestMeta = new Map<string, Readonly<Record<string, unknown>>>();\n\tprivate _runtimeMeta = new Map<string, Readonly<Record<string, unknown>>>();\n\tprivate _resolvedMetaCache = new Map<string, Readonly<Record<string, unknown>>>();\n\tprivate _routeNames: string[] = [];\n\n\tconstructor(...args: ConstructorParameters<typeof MobileRouter>) {\n\t\tconst [routes, config, owner, ...rest] = args;\n\t\tconst rawConfig = config as Record<string, unknown> | undefined;\n\t\tconst isRecordConfig = isRecord(rawConfig);\n\t\tconst { guardRouter, ...cleanConfig } = isRecordConfig ? rawConfig : ({} as Record<string, unknown>);\n\t\tsuper(routes, isRecordConfig ? (cleanConfig as typeof config) : config, owner, ...rest);\n\t\tthis._options = normalizeGuardRouterOptions(guardRouter);\n\n\t\t// Collect route names from the constructor's routes parameter for pattern-tree traversal.\n\t\tif (Array.isArray(routes)) {\n\t\t\tthis._routeNames = routes\n\t\t\t\t.filter((r): r is { name: string } => isRecord(r) && typeof r.name === \"string\")\n\t\t\t\t.map((r) => r.name);\n\t\t} else if (isRecord(routes)) {\n\t\t\tthis._routeNames = Object.keys(routes);\n\t\t}\n\n\t\tif (isRecord(guardRouter) && guardRouter.routeMeta !== undefined) {\n\t\t\tif (isRecord(guardRouter.routeMeta)) {\n\t\t\t\tfor (const [routeName, meta] of Object.entries(guardRouter.routeMeta)) {\n\t\t\t\t\tif (isRecord(meta)) {\n\t\t\t\t\t\tthis._manifestMeta.set(routeName, Object.freeze({ ...meta }));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tLog.warning(\n\t\t\t\t\t\t\t`guardRouter.routeMeta[\"${routeName}\"]: expected object, skipping`,\n\t\t\t\t\t\t\tJSON.stringify(meta),\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tLog.warning(\n\t\t\t\t\t\"guardRouter.routeMeta: expected object, skipping\",\n\t\t\t\t\tJSON.stringify(guardRouter.routeMeta),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (isRecord(guardRouter) && guardRouter.guards !== undefined) {\n\t\t\tlet componentNamespace = \"\";\n\t\t\tif (owner) {\n\t\t\t\tconst appConfig = owner.getManifestEntry(\"sap.app\") as Record<string, unknown> | undefined;\n\t\t\t\tif (isRecord(appConfig) && typeof appConfig.id === \"string\") {\n\t\t\t\t\tcomponentNamespace = appConfig.id;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._pendingGuardDescriptors = parseGuardDescriptors(guardRouter.guards, componentNamespace);\n\n\t\t\t// Fire-and-forget preload hint: warm the module cache so lazy\n\t\t\t// wrappers resolve synchronously on first navigation.\n\t\t\t// Block mode loads modules itself in initialize().\n\t\t\tif (this._pendingGuardDescriptors.length > 0 && this._options.guardLoading === \"lazy\") {\n\t\t\t\tconst uniquePaths = [...new Set(this._pendingGuardDescriptors.map((d) => d.modulePath))];\n\t\t\t\tsap.ui.require(uniquePaths);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Initialize the router. When manifest guards are declared and\n\t * `guardLoading` is `\"block\"`, module loading starts and\n\t * `super.initialize()` is deferred until all modules are loaded.\n\t * In `\"lazy\"` mode, lazy wrappers are registered synchronously\n\t * and `super.initialize()` is called immediately.\n\t *\n\t * @override sap.ui.core.routing.Router#initialize\n\t * @since 1.0.1\n\t */\n\toverride initialize(): this {\n\t\tif (this._pendingGuardDescriptors.length === 0) {\n\t\t\treturn super.initialize();\n\t\t}\n\n\t\tconst descriptors = this._pendingGuardDescriptors;\n\t\tthis._pendingGuardDescriptors = [];\n\t\tthis._sourceDescriptors = descriptors;\n\n\t\tconst expandedDescriptors =\n\t\t\tthis._options.inheritance === \"pattern-tree\" ? this._expandGuardDescriptors(descriptors) : descriptors;\n\n\t\tif (this._options.guardLoading === \"lazy\") {\n\t\t\tthis._registerLazyGuards(expandedDescriptors);\n\t\t\treturn super.initialize();\n\t\t}\n\n\t\t// \"block\" mode: load all modules, then initialize.\n\t\t// Guard against destroy() being called while modules are still loading.\n\t\tthis._loadAndRegisterGuards(expandedDescriptors)\n\t\t\t.then(() => {\n\t\t\t\tif (!this._destroyed) super.initialize();\n\t\t\t})\n\t\t\t.catch((err: unknown) => {\n\t\t\t\tif (this._destroyed) return;\n\t\t\t\tLog.error(\n\t\t\t\t\t\"guardRouter.guards: module loading failed, initializing without manifest guards\",\n\t\t\t\t\tString(err),\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tsuper.initialize();\n\t\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add a route dynamically and integrate it into pattern-tree inheritance.\n\t *\n\t * Appends the route name to the internal route list so that\n\t * `_collectRoutePatterns()` includes it in subsequent inheritance\n\t * lookups, clears the metadata cache, and registers any inherited\n\t * manifest guards when `inheritance` is `\"pattern-tree\"`.\n\t *\n\t * @param oConfig - Route configuration object as defined by `sap.ui.core.routing.Route`.\n\t * @param rest - Additional arguments forwarded to the parent `addRoute`.\n\t * @override sap.ui.core.routing.Router#addRoute\n\t * @since 1.6.0\n\t */\n\toverride addRoute(oConfig: $RouteSettings, ...rest: unknown[]): void {\n\t\t// @ts-expect-error -- oParent is required in the type declaration but optional at runtime\n\t\tsuper.addRoute(oConfig, ...rest);\n\n\t\t// Skip when called by the parent constructor before field initializers have run.\n\t\t// Routes from the constructor args are captured in _routeNames by the constructor body.\n\t\tif (!this._routeNames) return;\n\n\t\tconst name = oConfig.name;\n\t\tif (typeof name !== \"string\") return;\n\t\tif (this._routeNames.includes(name)) return;\n\n\t\tthis._routeNames.push(name);\n\t\tthis._resolvedMetaCache.clear();\n\n\t\tif (this._options.inheritance !== \"pattern-tree\") return;\n\t\tif (this._sourceDescriptors.length === 0) return;\n\n\t\tconst route = this.getRoute(name);\n\t\tif (!route) return;\n\t\tconst newPattern = route.getPattern();\n\t\tif (newPattern === undefined) return;\n\n\t\tconst newDescriptors = this._expandGuardDescriptorsForNewRoute(name, newPattern);\n\t\tif (newDescriptors.length === 0) return;\n\n\t\t// Always use lazy registration: if the module was loaded during\n\t\t// initialize() (block mode), the sync cache probe succeeds immediately.\n\t\t// This avoids an async gap between addRoute() and the first navigation.\n\t\tthis._registerLazyGuards(newDescriptors);\n\t}\n\n\t/**\n\t * Expand manifest guard descriptors for a single newly added route.\n\t *\n\t * For each source descriptor whose route is an ancestor of the new\n\t * route's pattern, emits a copy targeting the new route. Also emits\n\t * copies for existing routes that are descendants of the new route\n\t * (in case the new route has declared guards). Sorted by depth.\n\t */\n\tprivate _expandGuardDescriptorsForNewRoute(newName: string, newPattern: string): GuardDescriptor[] {\n\t\tconst result: GuardDescriptor[] = [];\n\n\t\tfor (const descriptor of this._sourceDescriptors) {\n\t\t\tif (descriptor.route === \"*\") continue;\n\n\t\t\tif (descriptor.route !== newName) {\n\t\t\t\t// Check if the source descriptor's route is an ancestor of the new route.\n\t\t\t\tconst ancestorRoute = this.getRoute(descriptor.route);\n\t\t\t\tconst ancestorPattern = ancestorRoute?.getPattern();\n\t\t\t\tif (ancestorPattern !== undefined && isPatternAncestor(ancestorPattern, newPattern)) {\n\t\t\t\t\tresult.push({ ...descriptor, route: newName });\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// The new route itself has a source descriptor: expand to existing descendants.\n\t\t\t\tfor (const { name, pattern } of this._collectRoutePatterns()) {\n\t\t\t\t\tif (name === newName) continue;\n\t\t\t\t\tif (isPatternAncestor(newPattern, pattern)) {\n\t\t\t\t\t\tresult.push({ ...descriptor, route: name });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Sort by pattern depth (ancestor guards run before descendant guards).\n\t\treturn result.toSorted((a, b) => {\n\t\t\tconst pa = this.getRoute(a.route)?.getPattern() ?? \"\";\n\t\t\tconst pb = this.getRoute(b.route)?.getPattern() ?? \"\";\n\t\t\treturn patternSegments(pa).length - patternSegments(pb).length;\n\t\t});\n\t}\n\n\t/**\n\t * Register a global guard that runs for every navigation.\n\t *\n\t * @param guard - Guard function to register. Non-functions are ignored with a warning.\n\t * @returns `this` for chaining.\n\t * @since 1.0.1\n\t */\n\taddGuard(guard: GuardFn): this {\n\t\tif (!this._isFn(guard, \"addGuard\")) return this;\n\t\tthis._pipeline.addGlobalGuard(guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove a previously registered global guard.\n\t *\n\t * @param guard - Guard function to remove by reference. Non-functions are ignored with a warning.\n\t * @returns `this` for chaining.\n\t * @since 1.0.1\n\t */\n\tremoveGuard(guard: GuardFn): this {\n\t\tif (!this._isFn(guard, \"removeGuard\")) return this;\n\t\tthis._pipeline.removeGlobalGuard(guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Register a guard for a specific route.\n\t *\n\t * Accepts either a guard function (registered as an enter guard) or a\n\t * configuration object with `beforeEnter` and/or `beforeLeave` guards.\n\t *\n\t * @param routeName - Route name as defined in `manifest.json`. If the route is unknown, the {@link GuardRouterOptions.unknownRouteRegistration} policy applies (default: warn).\n\t * @param guard - Guard function or {@link RouteGuardConfig} object.\n\t * @returns `this` for chaining.\n\t * @since 1.0.1\n\t */\n\taddRouteGuard(routeName: string, guard: GuardFn | RouteGuardConfig): this {\n\t\tif (isRouteGuardConfig(guard)) {\n\t\t\tif (!this._handleUnknownRouteRegistration(routeName, \"addRouteGuard\")) {\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tlet hasHandler = false;\n\n\t\t\tif (guard.beforeEnter !== undefined) {\n\t\t\t\thasHandler = true;\n\t\t\t\tif (this._isFn(guard.beforeEnter, \"addRouteGuard\", routeName)) {\n\t\t\t\t\tthis._pipeline.addEnterGuard(routeName, guard.beforeEnter);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (guard.beforeLeave !== undefined) {\n\t\t\t\thasHandler = true;\n\t\t\t\tif (this._isFn(guard.beforeLeave, \"addRouteGuard\", routeName)) {\n\t\t\t\t\tthis._pipeline.addLeaveGuard(routeName, guard.beforeLeave);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!hasHandler) {\n\t\t\t\tLog.info(\"addRouteGuard: config has no beforeEnter or beforeLeave\", routeName, LOG_COMPONENT);\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif (!this._isFn(guard, \"addRouteGuard\", routeName)) return this;\n\t\tif (!this._handleUnknownRouteRegistration(routeName, \"addRouteGuard\")) {\n\t\t\treturn this;\n\t\t}\n\t\tthis._pipeline.addEnterGuard(routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Remove a guard from a specific route.\n\t *\n\t * Accepts the same forms as `addRouteGuard`: a guard function removes\n\t * an enter guard; a configuration object removes `beforeEnter` and/or\n\t * `beforeLeave` by reference.\n\t *\n\t * @param routeName - Route name as defined in `manifest.json`.\n\t * @param guard - Guard function or {@link RouteGuardConfig} object to remove by reference.\n\t * @returns `this` for chaining.\n\t * @since 1.0.1\n\t */\n\tremoveRouteGuard(routeName: string, guard: GuardFn | RouteGuardConfig): this {\n\t\tif (isRouteGuardConfig(guard)) {\n\t\t\tif (typeof guard.beforeEnter === \"function\") {\n\t\t\t\tthis.removeRouteGuard(routeName, guard.beforeEnter);\n\t\t\t}\n\t\t\tif (typeof guard.beforeLeave === \"function\") {\n\t\t\t\tthis.removeLeaveGuard(routeName, guard.beforeLeave);\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif (!this._isFn(guard, \"removeRouteGuard\", routeName)) return this;\n\t\tthis._pipeline.removeEnterGuard(routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Register a leave guard for a specific route.\n\t *\n\t * Leave guards run when navigating **away from** the route, before any\n\t * enter guards for the target route. They answer the binary question\n\t * \"can I leave?\" and return only a boolean (no redirects).\n\t *\n\t * @param routeName - Route name as defined in `manifest.json`. If the route is unknown, the {@link GuardRouterOptions.unknownRouteRegistration} policy applies (default: warn).\n\t * @param guard - Leave guard function to register. Non-functions are ignored with a warning.\n\t * @returns `this` for chaining.\n\t * @since 1.0.1\n\t */\n\taddLeaveGuard(routeName: string, guard: LeaveGuardFn): this {\n\t\tif (!this._isFn(guard, \"addLeaveGuard\", routeName)) return this;\n\t\tif (!this._handleUnknownRouteRegistration(routeName, \"addLeaveGuard\")) {\n\t\t\treturn this;\n\t\t}\n\t\tthis._pipeline.addLeaveGuard(routeName, guard);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Disambiguate the `navTo()` overload shapes into resolved arguments.\n\t *\n\t * UI5's native `navTo` has two signatures where the third parameter is either\n\t * `componentTargetInfo` (object) or `bReplace` (boolean). This method normalizes\n\t * both forms so the rest of `navTo` can work with a single set of variables.\n\t */\n\tprivate _resolveNavToArgs(\n\t\tcomponentTargetInfoOrReplace?: Record<string, ComponentTargetParameters> | boolean,\n\t\treplaceOrOptions?: boolean | GuardNavToOptions,\n\t\toptions?: GuardNavToOptions,\n\t): {\n\t\tcomponentTargetInfo?: Record<string, ComponentTargetParameters>;\n\t\treplace?: boolean;\n\t\tguardOptions?: GuardNavToOptions;\n\t} {\n\t\tif (typeof componentTargetInfoOrReplace === \"boolean\") {\n\t\t\t// Short form: navTo(name, params, replace, options?)\n\t\t\treturn {\n\t\t\t\treplace: componentTargetInfoOrReplace,\n\t\t\t\tguardOptions:\n\t\t\t\t\ttypeof replaceOrOptions === \"object\" && replaceOrOptions !== null ? replaceOrOptions : undefined,\n\t\t\t};\n\t\t}\n\t\t// Long form: navTo(name, params, componentTargetInfo, replace, options?)\n\t\treturn {\n\t\t\tcomponentTargetInfo: componentTargetInfoOrReplace,\n\t\t\treplace: typeof replaceOrOptions === \"boolean\" ? replaceOrOptions : undefined,\n\t\t\tguardOptions: options,\n\t\t};\n\t}\n\n\t/** Return `true` when the value is a function; otherwise log a warning. */\n\tprivate _isFn(value: unknown, method: string, detail?: string): boolean {\n\t\tif (typeof value === \"function\") return true;\n\t\tLog.warning(`${method}: not a function, ignoring`, detail, LOG_COMPONENT);\n\t\treturn false;\n\t}\n\n\t/**\n\t * Handle guard registration for a potentially unknown route.\n\t * Returns `true` if registration should proceed, `false` if not.\n\t */\n\tprivate _handleUnknownRouteRegistration(routeName: string, methodName: string): boolean {\n\t\tif (this.getRoute(routeName)) return true;\n\n\t\tswitch (this._options.unknownRouteRegistration) {\n\t\t\tcase \"ignore\":\n\t\t\t\treturn true;\n\t\t\tcase \"throw\":\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`${methodName} called for unknown route \"${routeName}\". ` +\n\t\t\t\t\t\t`Set guardRouter.unknownRouteRegistration to \"warn\" or \"ignore\" to allow this.`,\n\t\t\t\t);\n\t\t\tcase \"warn\":\n\t\t\tdefault:\n\t\t\t\tLog.warning(`${methodName}: unknown route, guard registered anyway`, routeName, LOG_COMPONENT);\n\t\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * Remove a leave guard from a specific route.\n\t *\n\t * @param routeName - Route name as defined in `manifest.json`.\n\t * @param guard - Leave guard function to remove by reference. Non-functions are ignored with a warning.\n\t * @returns `this` for chaining.\n\t * @since 1.0.1\n\t */\n\tremoveLeaveGuard(routeName: string, guard: LeaveGuardFn): this {\n\t\tif (!this._isFn(guard, \"removeLeaveGuard\", routeName)) return this;\n\t\tthis._pipeline.removeLeaveGuard(routeName, guard);\n\t\treturn this;\n\t}\n\n\tprivate static readonly _EMPTY_META: Readonly<Record<string, unknown>> = Object.freeze({});\n\n\t/**\n\t * Return the resolved metadata for a route.\n\t *\n\t * When `inheritance` is `\"pattern-tree\"`, walks the ancestor chain and\n\t * shallow-merges metadata shallowest-first (child values win on conflict).\n\t * Both manifest and runtime metadata participate in inheritance.\n\t * The router caches results; {@link setRouteMeta} and `addRoute()` clear the cache.\n\t *\n\t * Logs a warning for unknown non-empty route names and returns an empty\n\t * frozen object. The empty string `\"\"` is treated as a valid root route.\n\t *\n\t * @param routeName - Route name as defined in `manifest.json`.\n\t * @returns Frozen record of metadata key-value pairs, or an empty frozen object if the route has no metadata.\n\t * @since 1.6.0\n\t */\n\tgetRouteMeta(routeName: string): Readonly<Record<string, unknown>> {\n\t\t// Empty string is a valid root route name (initial state before first navigation)\n\t\tif (routeName !== \"\" && !this.getRoute(routeName)) {\n\t\t\tLog.warning(\"getRouteMeta: unknown route, returning empty metadata\", routeName, LOG_COMPONENT);\n\t\t\treturn Router._EMPTY_META;\n\t\t}\n\n\t\t// Cache hit\n\t\tconst cached = this._resolvedMetaCache.get(routeName);\n\t\tif (cached) return cached;\n\n\t\tlet result: Readonly<Record<string, unknown>>;\n\n\t\tif (this._options.inheritance === \"pattern-tree\") {\n\t\t\tresult = this._resolveInheritedMeta(routeName);\n\t\t} else {\n\t\t\tresult = this._resolveFlatMeta(routeName);\n\t\t}\n\n\t\tif (Object.keys(result).length === 0) {\n\t\t\tthis._resolvedMetaCache.set(routeName, Router._EMPTY_META);\n\t\t\treturn Router._EMPTY_META;\n\t\t}\n\n\t\tthis._resolvedMetaCache.set(routeName, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Set runtime metadata for a route.\n\t *\n\t * Runtime metadata is merged on top of any manifest-declared metadata\n\t * when retrieved via {@link getRouteMeta}. When `inheritance` is\n\t * `\"pattern-tree\"`, descendant routes also see the updated values.\n\t * Invalidates the resolved-metadata cache. Non-object values are\n\t * ignored with a warning. Subject to the `unknownRouteRegistration` policy.\n\t *\n\t * @param routeName - Route name as defined in `manifest.json`.\n\t * @param meta - Plain object of metadata key-value pairs.\n\t * @returns `this` for chaining.\n\t * @since 1.6.0\n\t */\n\tsetRouteMeta(routeName: string, meta: Record<string, unknown>): this {\n\t\tif (!isRecord(meta)) {\n\t\t\tLog.warning(\"setRouteMeta: expected object, ignoring\", routeName, LOG_COMPONENT);\n\t\t\treturn this;\n\t\t}\n\t\tif (routeName !== \"\" && !this._handleUnknownRouteRegistration(routeName, \"setRouteMeta\")) {\n\t\t\treturn this;\n\t\t}\n\t\tthis._runtimeMeta.set(routeName, Object.freeze({ ...meta }));\n\t\tthis._resolvedMetaCache.clear();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Return a Promise that settles when the current guard pipeline finishes.\n\t *\n\t * If a navigation is pending, the Promise resolves when that pipeline settles.\n\t * If no navigation is pending, it resolves immediately with the most recent\n\t * settlement result. Before any navigation has settled, it falls back to a\n\t * synthetic `Committed` result derived from the router's current route/hash\n\t * state. After `stop()`, that idle fallback reports empty route/hash values\n\t * until a new navigation settles.\n\t *\n\t * @returns Promise that resolves with a {@link NavigationResult} once the pipeline settles.\n\t * @since 1.2.0\n\t */\n\tnavigationSettled(): Promise<NavigationResult> {\n\t\tif (this._phase.kind !== \"evaluating\") {\n\t\t\treturn Promise.resolve(\n\t\t\t\tthis._lastSettlement ?? {\n\t\t\t\t\tstatus: NavigationOutcome.Committed,\n\t\t\t\t\troute: this._currentRoute,\n\t\t\t\t\thash: this._currentHash ?? \"\",\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\treturn new Promise((resolve) => {\n\t\t\tthis._settlementResolvers.push(resolve);\n\t\t});\n\t}\n\n\t/**\n\t * Attach an event handler for the `navigationSettled` event.\n\t *\n\t * Fires synchronously after every guard pipeline settlement with\n\t * a {@link NavigationResult} payload. Unlike the one-shot\n\t * `navigationSettled()` Promise, this event fires for every\n\t * navigation outcome without re-registration.\n\t *\n\t * @param oData - Application-specific payload passed to the handler as second argument.\n\t * @param fnFunction - The function to be called when the event occurs.\n\t * @param oListener - Context object to call the event handler with. Defaults to this Router.\n\t * @since 1.3.0\n\t */\n\tattachNavigationSettled(\n\t\toData: object,\n\t\tfnFunction: (evt: Router$NavigationSettledEvent) => void,\n\t\toListener?: object,\n\t): this;\n\tattachNavigationSettled(fnFunction: (evt: Router$NavigationSettledEvent) => void, oListener?: object): this;\n\tattachNavigationSettled(oData: unknown, fnFunction?: unknown, oListener?: unknown): this {\n\t\tthis.attachEvent(\n\t\t\t\"navigationSettled\",\n\t\t\toData as object,\n\t\t\tfnFunction as (...args: unknown[]) => void,\n\t\t\toListener as object,\n\t\t);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Detach a previously attached `navigationSettled` event handler.\n\t *\n\t * The passed parameters must match those used for registration with\n\t * {@link #attachNavigationSettled} beforehand.\n\t *\n\t * @param fnFunction - The handler function to detach.\n\t * @param oListener - Context object on which the given function had to be called.\n\t * @since 1.3.0\n\t */\n\tdetachNavigationSettled(fnFunction: (evt: Router$NavigationSettledEvent) => void, oListener?: object): this {\n\t\tthis.detachEvent(\"navigationSettled\", fnFunction as (...args: unknown[]) => void, oListener);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Drain all settlement resolvers with the given result and fire\n\t * the `navigationSettled` event.\n\t */\n\tprivate _flushSettlement(result: NavigationResult): void {\n\t\tthis._lastSettlement = result;\n\t\tconst resolvers = this._settlementResolvers;\n\t\tthis._settlementResolvers = [];\n\t\tfor (const resolve of resolvers) {\n\t\t\tresolve(result);\n\t\t}\n\t\tthis.fireEvent(\"navigationSettled\", result);\n\t}\n\n\t/**\n\t * Navigate to a route with preflight guard evaluation.\n\t *\n\t * For programmatic navigation, guards run BEFORE the hash changes.\n\t * This prevents history pollution: blocked navigations never push a\n\t * history entry, and redirected navigations go directly to the final\n\t * target.\n\t *\n\t * Same-hash navigations are deduped: if the target hash matches\n\t * `_currentHash`, any pending navigation is cancelled and the call\n\t * returns without navigating. If it matches the in-flight attempt's\n\t * hash, the in-flight preflight continues undisturbed.\n\t *\n\t * When all guards are synchronous, the decision and the resulting\n\t * hash change happen in the same tick. When any guard returns a\n\t * Promise, `navTo()` returns `this` immediately and defers the\n\t * hash change to when the guard resolves.\n\t *\n\t * Assumes `super.navTo()` calls `HashChanger.setHash()` which fires\n\t * `hashChanged` synchronously, causing `parse()` to re-enter in the\n\t * same call stack (validated by test).\n\t *\n\t * @override sap.ui.core.routing.Router#navTo\n\t * @since 1.0.1\n\t */\n\toverride navTo(\n\t\trouteName: string,\n\t\tparameters?: object,\n\t\tcomponentTargetInfo?: Record<string, ComponentTargetParameters>,\n\t\tbReplace?: boolean,\n\t): this;\n\toverride navTo(routeName: string, parameters?: object, bReplace?: boolean): this;\n\toverride navTo(routeName: string, parameters?: object, bReplace?: boolean, options?: GuardNavToOptions): this;\n\toverride navTo(\n\t\trouteName: string,\n\t\tparameters?: object,\n\t\tcomponentTargetInfo?: Record<string, ComponentTargetParameters>,\n\t\tbReplace?: boolean,\n\t\toptions?: GuardNavToOptions,\n\t): this;\n\toverride navTo(\n\t\trouteName: string,\n\t\tparameters?: object,\n\t\tcomponentTargetInfoOrReplace?: Record<string, ComponentTargetParameters> | boolean,\n\t\treplaceOrOptions?: boolean | GuardNavToOptions,\n\t\toptions?: GuardNavToOptions,\n\t): this {\n\t\tconst { componentTargetInfo, replace, guardOptions } = this._resolveNavToArgs(\n\t\t\tcomponentTargetInfoOrReplace,\n\t\t\treplaceOrOptions,\n\t\t\toptions,\n\t\t);\n\n\t\t// Redirect path: _redirect() calls this.navTo() while in committing/redirect phase.\n\t\t// Bypass preflight -- parse() will commit directly via the committing phase.\n\t\tif (this._phase.kind === \"committing\" && this._phase.origin === \"redirect\") {\n\t\t\tsuper.navTo(routeName, parameters, componentTargetInfo, replace);\n\t\t\treturn this;\n\t\t}\n\n\t\t// Resolve the target hash so we can build a guard context.\n\t\t// getURL() returns the hash pattern with parameters substituted.\n\t\tconst route = this.getRoute(routeName);\n\t\tif (!route) {\n\t\t\t// Unknown route -- let parent handle it (may fire bypassed event).\n\t\t\t// Cancel any pending async navigation so settlement resolvers drain\n\t\t\t// and the stale pipeline does not commit a superseded navigation.\n\t\t\tthis._cancelPendingNavigation();\n\t\t\tsuper.navTo(routeName, parameters, componentTargetInfo, replace);\n\t\t\treturn this;\n\t\t}\n\n\t\tconst targetHash = route.getURL(parameters ?? {});\n\t\tconst routeInfo = this.getRouteInfoByHash(targetHash);\n\t\tconst toRoute = routeInfo?.name ?? \"\";\n\n\t\t// Same-hash dedup: cancel any pending navigation and return without navigating.\n\t\tif (this._currentHash !== null && targetHash === this._currentHash) {\n\t\t\tthis._cancelPendingNavigation();\n\t\t\treturn this;\n\t\t}\n\n\t\t// Pending-hash dedup: if an async preflight for this exact hash is\n\t\t// already running, don't cancel and restart it.\n\t\tif (this._phase.kind === \"evaluating\" && targetHash === this._phase.attempt.hash) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Cancel any pending navigation (including previous async preflight).\n\t\tthis._cancelPendingNavigation();\n\n\t\tconst skipGuards = guardOptions?.skipGuards === true;\n\n\t\t// Bypass mode: skip guards for programmatic navTo() -- commit directly.\n\t\tif (skipGuards || this._options.navToPreflight === \"bypass\") {\n\t\t\tthis._phase = { kind: \"committing\", hash: targetHash, route: toRoute, origin: \"preflight\" };\n\t\t\tsuper.navTo(routeName, parameters, componentTargetInfo, replace);\n\t\t\t// Safety: if super.navTo didn't trigger parse (e.g. hash didn't change),\n\t\t\t// clear the marker to avoid stale state.\n\t\t\tif (this._phase.kind === \"committing\" && this._phase.hash === targetHash) {\n\t\t\t\tthis._commitNavigation(targetHash, toRoute);\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\t// Off mode: defer guard evaluation to parse() fallback.\n\t\tif (this._options.navToPreflight === \"off\") {\n\t\t\tsuper.navTo(routeName, parameters, componentTargetInfo, replace);\n\t\t\treturn this;\n\t\t}\n\n\t\t// Default \"guard\" mode: evaluate guards before hash change.\n\t\tconst controller = new AbortController();\n\t\tconst generation = this._parseGeneration;\n\n\t\tthis._phase = {\n\t\t\tkind: \"evaluating\",\n\t\t\tattempt: { hash: targetHash, route: toRoute, controller, generation },\n\t\t};\n\n\t\tconst context = this._createGuardContext(toRoute, targetHash, routeInfo, controller.signal);\n\n\t\tconst decision = this._pipeline.evaluate(context);\n\n\t\tif (isPromiseLike(decision)) {\n\t\t\tdecision\n\t\t\t\t.then((d: GuardDecision) => {\n\t\t\t\t\tif (generation !== this._parseGeneration || this._phase.kind !== \"evaluating\") {\n\t\t\t\t\t\tLog.debug(\n\t\t\t\t\t\t\t\"Async preflight result discarded (superseded by newer navigation)\",\n\t\t\t\t\t\t\ttargetHash,\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tthis._applyPreflightDecision(\n\t\t\t\t\t\td,\n\t\t\t\t\t\trouteName,\n\t\t\t\t\t\tparameters,\n\t\t\t\t\t\tcomponentTargetInfo,\n\t\t\t\t\t\treplace,\n\t\t\t\t\t\ttargetHash,\n\t\t\t\t\t\ttoRoute,\n\t\t\t\t\t\tcontext.bag,\n\t\t\t\t\t);\n\t\t\t\t})\n\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\t// Only check generation here, not phase. If _redirect threw and its\n\t\t\t\t\t// finally already reset phase to idle, we still need to drain\n\t\t\t\t\t// settlement resolvers via _errorNavigation.\n\t\t\t\t\tif (generation !== this._parseGeneration) return;\n\t\t\t\t\tLog.error(\n\t\t\t\t\t\t`Async preflight guard failed for route \"${routeName}\", navigation failed`,\n\t\t\t\t\t\tString(error),\n\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t);\n\t\t\t\t\tthis._errorNavigation(error, targetHash, false);\n\t\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\t// Sync path: apply the decision immediately.\n\t\tthis._applyPreflightDecision(\n\t\t\tdecision,\n\t\t\trouteName,\n\t\t\tparameters,\n\t\t\tcomponentTargetInfo,\n\t\t\treplace,\n\t\t\ttargetHash,\n\t\t\ttoRoute,\n\t\t\tcontext.bag,\n\t\t);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Apply a preflight guard decision. For \"allow\", enter the committing\n\t * phase and call super.navTo(). For \"block\", flush settlement without\n\t * touching the hash. For \"redirect\", start a redirect chain.\n\t * For \"error\", flush Error settlement with the guard's error.\n\t *\n\t * @param decision - Normalized guard pipeline result.\n\t * @param routeName - Original route name passed to navTo().\n\t * @param parameters - Original route parameters.\n\t * @param componentTargetInfo - Optional component target info from the navTo() overload.\n\t * @param bReplace - Whether to replace the current history entry.\n\t * @param targetHash - Resolved hash for the target route.\n\t * @param toRoute - Resolved route name (may differ from routeName for nested routes).\n\t */\n\tprivate _applyPreflightDecision(\n\t\tdecision: GuardDecision,\n\t\trouteName: string,\n\t\tparameters: object | undefined,\n\t\tcomponentTargetInfo: Record<string, ComponentTargetParameters> | undefined,\n\t\tbReplace: boolean | undefined,\n\t\ttargetHash: string,\n\t\ttoRoute: string,\n\t\tbag: Map<string, unknown>,\n\t): void {\n\t\tswitch (decision.action) {\n\t\t\tcase \"allow\":\n\t\t\t\tthis._phase = { kind: \"committing\", hash: targetHash, route: toRoute, origin: \"preflight\" };\n\t\t\t\tsuper.navTo(routeName, parameters, componentTargetInfo, bReplace);\n\t\t\t\t// Safety: if super.navTo didn't trigger parse (e.g. hash didn't change),\n\t\t\t\t// clear the marker to avoid stale state.\n\t\t\t\tif (this._phase.kind === \"committing\" && this._phase.hash === targetHash) {\n\t\t\t\t\t// Hash didn't change, so parse() wasn't called. Commit manually.\n\t\t\t\t\tthis._commitNavigation(targetHash, toRoute);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"block\":\n\t\t\t\tthis._blockNavigation(targetHash, false);\n\t\t\t\tbreak;\n\t\t\tcase \"redirect\":\n\t\t\t\tthis._startRedirectChain(decision.target, targetHash, false, bag);\n\t\t\t\tbreak;\n\t\t\tcase \"error\":\n\t\t\t\tthis._errorNavigation(decision.error, targetHash, false);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Intercept hash changes and run the guard pipeline before route matching.\n\t *\n\t * Called by the HashChanger on every `hashChanged` event. Runs leave guards\n\t * (current route), then global + route-specific enter guards (target route).\n\t * Stays synchronous when all guards return plain values; falls back to async\n\t * when a guard returns a Promise. A generation counter discards stale results\n\t * when navigations overlap.\n\t *\n\t * @param newHash - The new hash fragment from the URL.\n\t * @override sap.ui.core.routing.Router#parse\n\t * @since 1.0.1\n\t */\n\toverride parse(newHash: string): void {\n\t\tif (this._suppressedHash !== null) {\n\t\t\tif (newHash === this._suppressedHash) {\n\t\t\t\tthis._suppressedHash = null;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._suppressedHash = null;\n\t\t}\n\n\t\tif (this._phase.kind === \"committing\") {\n\t\t\tthis._commitNavigation(\n\t\t\t\tnewHash,\n\t\t\t\tthis._phase.route !== \"\" ? this._phase.route : (this.getRouteInfoByHash(newHash)?.name ?? \"\"),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._currentHash !== null && newHash === this._currentHash) {\n\t\t\tthis._cancelPendingNavigation();\n\t\t\treturn;\n\t\t}\n\n\t\tconst routeInfo = this.getRouteInfoByHash(newHash);\n\t\tconst toRoute = routeInfo?.name ?? \"\";\n\n\t\tthis._cancelPendingNavigation();\n\n\t\tconst controller = new AbortController();\n\t\tconst generation = this._parseGeneration;\n\n\t\tthis._phase = {\n\t\t\tkind: \"evaluating\",\n\t\t\tattempt: { hash: newHash, route: toRoute, controller, generation },\n\t\t};\n\n\t\tconst context = this._createGuardContext(toRoute, newHash, routeInfo, controller.signal);\n\n\t\tconst decision = this._pipeline.evaluate(context);\n\n\t\tif (isPromiseLike(decision)) {\n\t\t\tdecision\n\t\t\t\t.then((d: GuardDecision) => {\n\t\t\t\t\tif (generation !== this._parseGeneration || this._phase.kind !== \"evaluating\") {\n\t\t\t\t\t\tLog.debug(\n\t\t\t\t\t\t\t\"Async guard result discarded (superseded by newer navigation)\",\n\t\t\t\t\t\t\tnewHash,\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tthis._applyDecision(d, newHash, toRoute, context.bag);\n\t\t\t\t})\n\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\t// Only check generation here, not phase. If _redirect threw and its\n\t\t\t\t\t// finally already reset phase to idle, we still need to drain\n\t\t\t\t\t// settlement resolvers via _errorNavigation.\n\t\t\t\t\tif (generation !== this._parseGeneration) return;\n\t\t\t\t\tLog.error(\n\t\t\t\t\t\t`Guard pipeline failed for \"${newHash}\", navigation failed`,\n\t\t\t\t\t\tString(error),\n\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t);\n\t\t\t\t\tthis._errorNavigation(error, newHash);\n\t\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tthis._applyDecision(decision, newHash, toRoute, context.bag);\n\t}\n\n\t/**\n\t * Stop listening to hash changes and reset guard state.\n\t *\n\t * Resets `_currentRoute` and `_currentHash` so that a subsequent\n\t * `initialize()` re-parses the current hash and fires `routeMatched`,\n\t * matching the native `sap.m.routing.Router` behavior.\n\t *\n\t * @override sap.ui.core.routing.Router#stop\n\t * @since 1.0.1\n\t */\n\toverride stop(): this {\n\t\t// Cancel first so in-flight navigationSettled() resolvers receive the\n\t\t// Cancelled result before _lastSettlement is cleared below.\n\t\tthis._cancelPendingNavigation();\n\t\tthis._suppressedHash = null;\n\t\tthis._currentRoute = \"\";\n\t\tthis._currentHash = null;\n\t\tthis._lastSettlement = null;\n\t\tsuper.stop();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Invalidate any in-flight async guard work. Bumps the generation counter\n\t * so pending `.then()` callbacks see they are stale, aborts the signal,\n\t * and transitions to idle.\n\t */\n\tprivate _cancelPendingNavigation(): void {\n\t\t++this._parseGeneration;\n\t\tif (this._phase.kind === \"evaluating\") {\n\t\t\tthis._phase.attempt.controller.abort();\n\t\t\tthis._flushSettlement({\n\t\t\t\tstatus: NavigationOutcome.Cancelled,\n\t\t\t\troute: this._currentRoute,\n\t\t\t\thash: this._currentHash ?? \"\",\n\t\t\t});\n\t\t}\n\t\tthis._phase = IDLE;\n\t}\n\n\t/**\n\t * Apply a guard decision for the parse() fallback path.\n\t */\n\tprivate _applyDecision(decision: GuardDecision, hash: string, route: string, bag: Map<string, unknown>): void {\n\t\tswitch (decision.action) {\n\t\t\tcase \"allow\":\n\t\t\t\tthis._phase = { kind: \"committing\", hash, route, origin: \"parse\" };\n\t\t\t\tthis._commitNavigation(hash, route);\n\t\t\t\tbreak;\n\t\t\tcase \"block\":\n\t\t\t\tthis._blockNavigation(hash);\n\t\t\t\tbreak;\n\t\t\tcase \"redirect\":\n\t\t\t\tthis._startRedirectChain(decision.target, hash, true, bag);\n\t\t\t\tbreak;\n\t\t\tcase \"error\":\n\t\t\t\tthis._errorNavigation(decision.error, hash);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Delegate to the parent router and update internal state.\n\t *\n\t * State is updated BEFORE calling parse to ensure that if event handlers\n\t * (e.g., routeMatched) trigger nested navigation, the leave guards will\n\t * run for the correct (new) route rather than the old one.\n\t */\n\tprivate _commitNavigation(hash: string, route?: string): void {\n\t\tconst wasRedirect = this._phase.kind === \"committing\" && this._phase.origin === \"redirect\";\n\t\tthis._currentHash = hash;\n\t\tthis._currentRoute = route ?? this.getRouteInfoByHash(hash)?.name ?? \"\";\n\t\t// Transition to idle before super.parse so that routeMatched/patternMatched\n\t\t// handlers that call navTo() go through the full guard pipeline.\n\t\tthis._phase = IDLE;\n\t\tthis._flushSettlement({\n\t\t\tstatus: wasRedirect\n\t\t\t\t? NavigationOutcome.Redirected\n\t\t\t\t: this._currentRoute === \"\"\n\t\t\t\t\t? NavigationOutcome.Bypassed\n\t\t\t\t\t: NavigationOutcome.Committed,\n\t\t\troute: this._currentRoute,\n\t\t\thash,\n\t\t});\n\t\tsuper.parse(hash);\n\t}\n\n\t/**\n\t * Evaluate guards on a redirect target and apply the resulting decision.\n\t *\n\t * Handles loop detection (visited-hash set + depth cap), unknown-route\n\t * fallback, sync/async guard evaluation, and recursive chaining when\n\t * the target's guard itself returns a redirect. All hops in a chain\n\t * share the same AbortSignal and generation counter from the original\n\t * navigation so that a superseding navigation correctly discards\n\t * in-flight redirect work.\n\t *\n\t * @param target - Redirect target: a route name string or {@link GuardRedirect} with parameters.\n\t * @param chain - Mutable context threaded through the redirect chain (visited set, signals, etc.).\n\t */\n\tprivate _redirect(target: string | GuardRedirect, chain: RedirectChainContext): void {\n\t\tconst targetName = typeof target === \"string\" ? target : target.route;\n\t\tlet targetHash: string | null = null;\n\t\tconst targetParameters = typeof target === \"string\" ? {} : (target.parameters ?? {});\n\t\tconst targetRoute = this.getRoute(targetName);\n\t\tif (targetRoute) {\n\t\t\ttry {\n\t\t\t\ttargetHash = targetRoute.getURL(targetParameters);\n\t\t\t} catch {\n\t\t\t\ttargetHash = null;\n\t\t\t}\n\t\t}\n\n\t\t// Loop detection: visited set (exact hash match) + depth cap.\n\t\tif (targetHash !== null && chain.visited.has(targetHash)) {\n\t\t\tLog.error(\n\t\t\t\t`Guard redirect loop detected: ${[...chain.visited, targetHash].join(\" -> \")}`,\n\t\t\t\tundefined,\n\t\t\t\tLOG_COMPONENT,\n\t\t\t);\n\t\t\tthis._blockNavigation(chain.attemptedHash, chain.restoreHash);\n\t\t\treturn;\n\t\t}\n\t\tif (chain.visited.size > MAX_REDIRECT_DEPTH) {\n\t\t\tLog.error(\n\t\t\t\t`Guard redirect chain exceeded maximum depth (${MAX_REDIRECT_DEPTH}): ${[...chain.visited].join(\" -> \")}`,\n\t\t\t\tundefined,\n\t\t\t\tLOG_COMPONENT,\n\t\t\t);\n\t\t\tthis._blockNavigation(chain.attemptedHash, chain.restoreHash);\n\t\t\treturn;\n\t\t}\n\t\tif (targetHash !== null) {\n\t\t\tchain.visited.add(targetHash);\n\t\t}\n\n\t\t// If the target route doesn't exist or the hash couldn't be resolved,\n\t\t// attempt navTo (parent may fire bypassed) and fall back to blocked.\n\t\tif (targetHash === null) {\n\t\t\tconst settlementBefore = this._lastSettlement;\n\t\t\tthis._phase = { kind: \"committing\", hash: \"\", route: targetName, origin: \"redirect\" };\n\t\t\ttry {\n\t\t\t\tif (typeof target === \"string\") {\n\t\t\t\t\tthis.navTo(target, {}, {}, true);\n\t\t\t\t} else {\n\t\t\t\t\tthis.navTo(target.route, target.parameters ?? {}, target.componentTargetInfo, true);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tif (this._phase.kind === \"committing\") {\n\t\t\t\t\tthis._phase = IDLE;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this._lastSettlement === settlementBefore) {\n\t\t\t\tLog.warning(\n\t\t\t\t\t`Guard redirect target \"${targetName}\" did not produce a navigation, treating as blocked`,\n\t\t\t\t\tundefined,\n\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t);\n\t\t\t\tthis._blockNavigation(chain.attemptedHash, chain.restoreHash);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Narrowed after the null-branch early return; const carries it into the async closure.\n\t\tconst resolvedHash: string = targetHash;\n\n\t\t// Build guard context for the redirect target.\n\t\tconst routeInfo = this.getRouteInfoByHash(resolvedHash);\n\t\tconst context: GuardContext = {\n\t\t\ttoRoute: routeInfo?.name ?? \"\",\n\t\t\ttoHash: resolvedHash,\n\t\t\ttoArguments: routeInfo?.arguments ?? {},\n\t\t\tfromRoute: chain.fromRoute,\n\t\t\tfromHash: chain.fromHash,\n\t\t\tsignal: chain.signal,\n\t\t\tbag: chain.bag,\n\t\t\ttoMeta: this.getRouteMeta(routeInfo?.name ?? \"\"),\n\t\t\tfromMeta: this.getRouteMeta(chain.fromRoute),\n\t\t};\n\n\t\tconst decision = this._pipeline.evaluate(context, { skipLeaveGuards: true });\n\n\t\tif (isPromiseLike(decision)) {\n\t\t\tdecision\n\t\t\t\t.then((d: GuardDecision) => {\n\t\t\t\t\tif (chain.generation !== this._parseGeneration) return;\n\t\t\t\t\tthis._applyRedirectDecision(d, target, resolvedHash, chain);\n\t\t\t\t})\n\t\t\t\t.catch((error: unknown) => {\n\t\t\t\t\tif (chain.generation !== this._parseGeneration) return;\n\t\t\t\t\tLog.error(\n\t\t\t\t\t\t`Guard pipeline failed during redirect chain for \"${targetName}\", navigation failed`,\n\t\t\t\t\t\tString(error),\n\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t);\n\t\t\t\t\tthis._errorNavigation(error, chain.attemptedHash, chain.restoreHash);\n\t\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tthis._applyRedirectDecision(decision, target, resolvedHash, chain);\n\t}\n\n\t/**\n\t * Apply a guard decision within a redirect chain. For \"allow\", enter\n\t * committing phase and delegate to navTo (which hits the existing bypass).\n\t * For \"block\", block the entire chain. For \"redirect\", recurse.\n\t *\n\t * @param decision - Normalized guard pipeline result for this hop.\n\t * @param target - The redirect target (route name or {@link GuardRedirect}).\n\t * @param targetHash - Resolved hash for the redirect target (guaranteed non-null).\n\t * @param chain - Shared redirect chain context with visited set, signals, etc.\n\t */\n\tprivate _applyRedirectDecision(\n\t\tdecision: GuardDecision,\n\t\ttarget: string | GuardRedirect,\n\t\ttargetHash: string,\n\t\tchain: RedirectChainContext,\n\t): void {\n\t\tswitch (decision.action) {\n\t\t\tcase \"allow\": {\n\t\t\t\tconst targetName = typeof target === \"string\" ? target : target.route;\n\t\t\t\tconst settlementBefore = this._lastSettlement;\n\t\t\t\tthis._phase = { kind: \"committing\", hash: targetHash, route: targetName, origin: \"redirect\" };\n\t\t\t\ttry {\n\t\t\t\t\tif (typeof target === \"string\") {\n\t\t\t\t\t\tthis.navTo(target, {}, {}, true);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.navTo(target.route, target.parameters ?? {}, target.componentTargetInfo, true);\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tif (this._phase.kind === \"committing\") {\n\t\t\t\t\t\tthis._phase = IDLE;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Safety net: if navTo didn't produce a settlement (e.g. unknown route\n\t\t\t\t// or redirect to current hash where HashChanger doesn't fire), handle it.\n\t\t\t\tif (this._lastSettlement === settlementBefore) {\n\t\t\t\t\tconst redirectsToCurrentHash = targetHash === (this._currentHash ?? \"\");\n\t\t\t\t\tif (redirectsToCurrentHash) {\n\t\t\t\t\t\tthis._phase = {\n\t\t\t\t\t\t\tkind: \"committing\",\n\t\t\t\t\t\t\thash: this._currentHash ?? \"\",\n\t\t\t\t\t\t\troute: this._currentRoute,\n\t\t\t\t\t\t\torigin: \"redirect\",\n\t\t\t\t\t\t};\n\t\t\t\t\t\tthis._commitNavigation(this._currentHash ?? \"\", this._currentRoute);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tLog.warning(\n\t\t\t\t\t\t`Guard redirect target \"${targetName}\" did not produce a navigation, treating as blocked`,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t);\n\t\t\t\t\tthis._blockNavigation(chain.attemptedHash, chain.restoreHash);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"block\":\n\t\t\t\tthis._blockNavigation(chain.attemptedHash, chain.restoreHash);\n\t\t\t\tbreak;\n\t\t\tcase \"redirect\":\n\t\t\t\tthis._redirect(decision.target, chain);\n\t\t\t\tbreak;\n\t\t\tcase \"error\":\n\t\t\t\tthis._errorNavigation(decision.error, chain.attemptedHash, chain.restoreHash);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Build a guard context for a new navigation.\n\t * Called by {@link navTo} (preflight path) and {@link parse} (browser-initiated path).\n\t */\n\tprivate _createGuardContext(\n\t\ttoRoute: string,\n\t\ttoHash: string,\n\t\trouteInfo: { arguments: Record<string, string | Record<string, string>> } | undefined,\n\t\tsignal: AbortSignal,\n\t): GuardContext {\n\t\treturn {\n\t\t\ttoRoute,\n\t\t\ttoHash,\n\t\t\ttoArguments: routeInfo?.arguments ?? {},\n\t\t\tfromRoute: this._currentRoute,\n\t\t\tfromHash: this._currentHash ?? \"\",\n\t\t\tsignal,\n\t\t\tbag: new Map(),\n\t\t\ttoMeta: this.getRouteMeta(toRoute),\n\t\t\tfromMeta: this.getRouteMeta(this._currentRoute),\n\t\t};\n\t}\n\n\t/**\n\t * Start a new redirect chain from the current evaluating phase.\n\t * Called by {@link _applyPreflightDecision} and {@link _applyDecision}\n\t * when a guard returns a redirect. Delegates to {@link _redirect} with\n\t * a fresh {@link RedirectChainContext}.\n\t */\n\tprivate _startRedirectChain(\n\t\ttarget: string | GuardRedirect,\n\t\thash: string,\n\t\trestoreHash: boolean,\n\t\tbag: Map<string, unknown>,\n\t): void {\n\t\tconst { attempt } = this._phase as PhaseEvaluating;\n\t\tconst visited = new Set<string>();\n\t\tvisited.add(hash);\n\t\tthis._redirect(target, {\n\t\t\tvisited,\n\t\t\tattemptedHash: hash,\n\t\t\trestoreHash,\n\t\t\tfromRoute: this._currentRoute,\n\t\t\tfromHash: this._currentHash ?? \"\",\n\t\t\tsignal: attempt.controller.signal,\n\t\t\tgeneration: attempt.generation,\n\t\t\tbag,\n\t\t});\n\t}\n\n\t/**\n\t * Clear pending state and flush a Blocked settlement.\n\t * When `restoreHash` is true (default), also restores the browser hash\n\t * to `_currentHash`. Preflight callers pass false because the hash was\n\t * never changed.\n\t */\n\tprivate _blockNavigation(attemptedHash?: string, restoreHash = true): void {\n\t\tthis._phase = IDLE;\n\t\tthis._flushSettlement({\n\t\t\tstatus: NavigationOutcome.Blocked,\n\t\t\troute: this._currentRoute,\n\t\t\thash: this._currentHash ?? \"\",\n\t\t});\n\t\tthis._restoreHashIfNeeded(attemptedHash, restoreHash);\n\t}\n\n\t/**\n\t * Clear pending state and flush an Error settlement.\n\t * Same structure as {@link _blockNavigation} but with `NavigationOutcome.Error`\n\t * and the error that caused the failure.\n\t */\n\tprivate _errorNavigation(error: unknown, attemptedHash?: string, restoreHash = true): void {\n\t\tthis._phase = IDLE;\n\t\tthis._flushSettlement({\n\t\t\tstatus: NavigationOutcome.Error,\n\t\t\troute: this._currentRoute,\n\t\t\thash: this._currentHash ?? \"\",\n\t\t\terror,\n\t\t});\n\t\tthis._restoreHashIfNeeded(attemptedHash, restoreHash);\n\t}\n\n\t/** Conditionally restore the browser hash after a blocked or errored navigation. */\n\tprivate _restoreHashIfNeeded(attemptedHash: string | undefined, restoreHash: boolean): void {\n\t\tif (!restoreHash) return;\n\t\tif (this._currentHash === null && attemptedHash && attemptedHash !== \"\") {\n\t\t\tthis._restoreHash(\"\", false);\n\t\t\treturn;\n\t\t}\n\t\tthis._restoreHash(this._currentHash ?? \"\");\n\t}\n\n\t/**\n\t * Restore the previous hash without creating a history entry.\n\t * Assumes replaceHash fires hashChanged synchronously (validated by test).\n\t * `_currentRoute` stays unchanged because the navigation never\n\t * committed. The user remains on the same logical route.\n\t */\n\tprivate _restoreHash(hash: string, suppressParse = true): void {\n\t\tconst hashChanger = this.getHashChanger();\n\t\tif (hashChanger) {\n\t\t\tthis._suppressedHash = suppressParse ? hash : null;\n\t\t\thashChanger.replaceHash(hash, HistoryDirection.Unknown);\n\t\t\tif (this._suppressedHash === hash) {\n\t\t\t\tthis._suppressedHash = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Collect all route names and their patterns from the router.\n\t * Skips routes whose pattern is undefined (no pattern configured).\n\t */\n\tprivate _collectRoutePatterns(): { name: string; pattern: string }[] {\n\t\tconst result: { name: string; pattern: string }[] = [];\n\t\tfor (const name of this._routeNames) {\n\t\t\tconst route = this.getRoute(name);\n\t\t\tif (route) {\n\t\t\t\tconst pattern = route.getPattern();\n\t\t\t\tif (pattern !== undefined) {\n\t\t\t\t\tresult.push({ name, pattern });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Expand guard descriptors to descendant routes when guard inheritance\n\t * is set to `\"pattern-tree\"`. Global (`\"*\"`) descriptors are kept as-is.\n\t * Descriptors are sorted by pattern depth (ancestor guards run before\n\t * descendant guards).\n\t */\n\tprivate _expandGuardDescriptors(descriptors: GuardDescriptor[]): GuardDescriptor[] {\n\t\tconst allRoutes = this._collectRoutePatterns();\n\t\tif (allRoutes.length === 0) return descriptors;\n\n\t\t// Build a name -> pattern map for quick lookup\n\t\tconst patternByName = new Map(allRoutes.map((r) => [r.name, r.pattern]));\n\n\t\tconst expanded: GuardDescriptor[] = [];\n\n\t\tfor (const descriptor of descriptors) {\n\t\t\texpanded.push(descriptor);\n\n\t\t\t// Global guards and routes without a known pattern are not expanded\n\t\t\tif (descriptor.route === \"*\") continue;\n\t\t\tconst ancestorPattern = patternByName.get(descriptor.route);\n\t\t\tif (ancestorPattern === undefined) continue;\n\n\t\t\t// Find descendant routes whose pattern extends the ancestor's pattern\n\t\t\tfor (const { name, pattern } of allRoutes) {\n\t\t\t\tif (name === descriptor.route) continue;\n\t\t\t\tif (isPatternAncestor(ancestorPattern, pattern)) {\n\t\t\t\t\texpanded.push({ ...descriptor, route: name });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Sort by pattern depth (segment count) so ancestor guards run first.\n\t\t// Global (\"*\") descriptors return 0 here -- their relative position is irrelevant\n\t\t// because GuardPipeline evaluates globals separately from route-specific guards.\n\t\t// oxlint-disable-next-line unicorn/no-array-sort -- expanded is a local array, mutation is intentional\n\t\treturn expanded.sort((a, b) => {\n\t\t\tif (a.route === \"*\" || b.route === \"*\") return 0;\n\t\t\tconst pa = patternByName.get(a.route) ?? \"\";\n\t\t\tconst pb = patternByName.get(b.route) ?? \"\";\n\t\t\treturn patternSegments(pa).length - patternSegments(pb).length;\n\t\t});\n\t}\n\n\t/**\n\t * Resolve metadata for a route without inheritance (flat merge of\n\t * manifest and runtime metadata).\n\t */\n\tprivate _resolveFlatMeta(routeName: string): Readonly<Record<string, unknown>> {\n\t\tconst manifest = this._manifestMeta.get(routeName);\n\t\tconst runtime = this._runtimeMeta.get(routeName);\n\t\tif (!manifest && !runtime) return Router._EMPTY_META;\n\t\tif (!runtime) return manifest ?? Router._EMPTY_META;\n\t\tif (!manifest) return Object.freeze({ ...runtime });\n\t\treturn Object.freeze({ ...manifest, ...runtime });\n\t}\n\n\t/**\n\t * Resolve metadata for a route with pattern-tree inheritance.\n\t * Walks ancestor patterns shallowest-first, merging manifest and\n\t * runtime metadata at each level, then overlays the route's own.\n\t */\n\tprivate _resolveInheritedMeta(routeName: string): Readonly<Record<string, unknown>> {\n\t\tconst allRoutes = this._collectRoutePatterns();\n\t\tconst routeEntry = allRoutes.find((r) => r.name === routeName);\n\t\tif (!routeEntry) return this._resolveFlatMeta(routeName);\n\n\t\t// Find ancestors that have declared metadata (manifest or runtime)\n\t\tconst ancestors = allRoutes.filter(\n\t\t\t(r) =>\n\t\t\t\tr.name !== routeName &&\n\t\t\t\t(this._manifestMeta.has(r.name) || this._runtimeMeta.has(r.name)) &&\n\t\t\t\tisPatternAncestor(r.pattern, routeEntry.pattern),\n\t\t);\n\t\t// oxlint-disable-next-line unicorn/no-array-sort -- ancestors is a fresh array from filter()\n\t\tancestors.sort((a, b) => patternSegments(a.pattern).length - patternSegments(b.pattern).length);\n\n\t\t// Merge shallowest-first: root ancestor -> deeper ancestors -> own manifest -> own runtime\n\t\tconst merged: Record<string, unknown> = {};\n\n\t\tfor (const ancestor of ancestors) {\n\t\t\tconst ancestorManifest = this._manifestMeta.get(ancestor.name);\n\t\t\tif (ancestorManifest) Object.assign(merged, ancestorManifest);\n\t\t\tconst ancestorRuntime = this._runtimeMeta.get(ancestor.name);\n\t\t\tif (ancestorRuntime) Object.assign(merged, ancestorRuntime);\n\t\t}\n\n\t\tconst ownManifest = this._manifestMeta.get(routeName);\n\t\tif (ownManifest) Object.assign(merged, ownManifest);\n\t\tconst ownRuntime = this._runtimeMeta.get(routeName);\n\t\tif (ownRuntime) Object.assign(merged, ownRuntime);\n\n\t\tif (Object.keys(merged).length === 0) return Router._EMPTY_META;\n\t\treturn Object.freeze(merged);\n\t}\n\n\t/**\n\t * Load guard modules individually via `sap.ui.require` and register\n\t * each resolved function with the appropriate guard API.\n\t *\n\t * Each module is loaded in its own `sap.ui.require` call so that a\n\t * single invalid path only skips that guard (with a warning) rather\n\t * than failing the entire batch. Once all loads settle, guards\n\t * register in declaration order. Registration errors (e.g. from\n\t * `unknownRouteRegistration: \"throw\"`) are caught per-module.\n\t */\n\tprivate _loadAndRegisterGuards(descriptors: GuardDescriptor[]): Promise<void> {\n\t\tconst promises = descriptors.map((descriptor) => {\n\t\t\treturn new Promise<{ descriptor: GuardDescriptor; moduleExport: unknown }>((resolve) => {\n\t\t\t\tsap.ui.require(\n\t\t\t\t\t[descriptor.modulePath],\n\t\t\t\t\t(moduleExport: unknown) => {\n\t\t\t\t\t\tresolve({ descriptor, moduleExport });\n\t\t\t\t\t},\n\t\t\t\t\t(err: Error) => {\n\t\t\t\t\t\tLog.warning(\n\t\t\t\t\t\t\t`guardRouter.guards: failed to load module \"${descriptor.modulePath}\", skipping`,\n\t\t\t\t\t\t\tString(err),\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tresolve({ descriptor, moduleExport: null });\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\t\treturn Promise.all(promises).then((results) => {\n\t\t\tfor (const { descriptor, moduleExport } of results) {\n\t\t\t\tif (moduleExport === null) continue;\n\t\t\t\tconst exports = resolveModuleExports(\n\t\t\t\t\tmoduleExport,\n\t\t\t\t\tdescriptor.modulePath,\n\t\t\t\t\tdescriptor.name,\n\t\t\t\t\tdescriptor.exportKey,\n\t\t\t\t);\n\t\t\t\tfor (const { fn } of exports) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis._registerGuardFromDescriptor(descriptor, fn);\n\t\t\t\t\t} catch (err: unknown) {\n\t\t\t\t\t\tLog.error(\n\t\t\t\t\t\t\t`guardRouter.guards: failed to register \"${descriptor.modulePath}\"`,\n\t\t\t\t\t\t\tString(err),\n\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Route a parsed guard descriptor to the correct registration method.\n\t */\n\tprivate _registerGuardFromDescriptor(descriptor: GuardDescriptor, guardFn: GuardFn): void {\n\t\tif (descriptor.route === \"*\") {\n\t\t\tthis.addGuard(guardFn);\n\t\t} else if (descriptor.type === \"leave\") {\n\t\t\tif (!this._handleUnknownRouteRegistration(descriptor.route, \"addLeaveGuard\")) return;\n\t\t\tthis._pipeline.addLeaveGuard(descriptor.route, guardFn);\n\t\t} else {\n\t\t\tthis.addRouteGuard(descriptor.route, guardFn);\n\t\t}\n\t}\n\n\t/**\n\t * Register lazy wrapper functions that load guard modules on first use.\n\t *\n\t * Cherry-picked descriptors (with exportKey) get one lazy wrapper each.\n\t * Bare-path descriptors try a sync cache probe first; if the module is\n\t * cached (preload likely finished), all guards are expanded immediately.\n\t * On cache miss, a single \"expander\" wrapper loads the module on first\n\t * navigation, registers remaining guards, and executes the first.\n\t */\n\tprivate _registerLazyGuards(descriptors: GuardDescriptor[]): void {\n\t\tfor (const descriptor of descriptors) {\n\t\t\tconst { modulePath, exportKey, name } = descriptor;\n\n\t\t\tif (exportKey !== undefined) {\n\t\t\t\t// Cherry-picked: one lazy wrapper, resolves to exactly one guard\n\t\t\t\tconst lazyGuard = (context: GuardContext): GuardResult | PromiseLike<GuardResult> => {\n\t\t\t\t\tconst cached = sap.ui.require(modulePath) as unknown;\n\t\t\t\t\tif (cached !== undefined) {\n\t\t\t\t\t\tconst exports = resolveModuleExports(cached, modulePath, name, exportKey);\n\t\t\t\t\t\tif (exports.length === 0) return true;\n\t\t\t\t\t\treturn exports[0].fn(context);\n\t\t\t\t\t}\n\t\t\t\t\treturn new Promise<GuardResult>((resolve, reject) => {\n\t\t\t\t\t\tsap.ui.require(\n\t\t\t\t\t\t\t[modulePath],\n\t\t\t\t\t\t\t(mod: unknown) => {\n\t\t\t\t\t\t\t\tconst exports = resolveModuleExports(mod, modulePath, name, exportKey);\n\t\t\t\t\t\t\t\tif (exports.length === 0) {\n\t\t\t\t\t\t\t\t\tresolve(true);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresolve(exports[0].fn(context));\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t(err: Error) => {\n\t\t\t\t\t\t\t\tLog.warning(\n\t\t\t\t\t\t\t\t\t`guardRouter.guards: lazy load of \"${modulePath}\" failed`,\n\t\t\t\t\t\t\t\t\tString(err),\n\t\t\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treject(err);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t\tthis._registerGuardFromDescriptor(descriptor, lazyGuard);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Bare-path: try sync expansion from cache (preload likely finished)\n\t\t\tconst cached = sap.ui.require(modulePath) as unknown;\n\t\t\tif (cached !== undefined) {\n\t\t\t\tconst exports = resolveModuleExports(cached, modulePath, name);\n\t\t\t\tfor (const exp of exports) {\n\t\t\t\t\tthis._registerGuardFromDescriptor(descriptor, exp.fn);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Cache miss: register an expander that loads, expands once, and runs guard[0].\n\t\t\t// NOTE: Guards 1..N are appended to the guard array on first invocation,\n\t\t\t// which means they execute AFTER any imperative guards registered between\n\t\t\t// initialize() and first navigation. This differs from block mode where\n\t\t\t// all guards occupy contiguous positions. In practice this is rare because\n\t\t\t// the preload hint fires in the constructor and modules are typically cached\n\t\t\t// by the time initialize() runs.\n\t\t\tlet expanded = false;\n\t\t\tconst lazyExpander = (context: GuardContext): PromiseLike<GuardResult> => {\n\t\t\t\treturn new Promise<GuardResult>((resolve, reject) => {\n\t\t\t\t\tsap.ui.require(\n\t\t\t\t\t\t[modulePath],\n\t\t\t\t\t\t(mod: unknown) => {\n\t\t\t\t\t\t\tconst exports = resolveModuleExports(mod, modulePath, name);\n\t\t\t\t\t\t\tif (exports.length === 0) {\n\t\t\t\t\t\t\t\tresolve(true);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!expanded) {\n\t\t\t\t\t\t\t\texpanded = true;\n\t\t\t\t\t\t\t\tfor (let i = 1; i < exports.length; i++) {\n\t\t\t\t\t\t\t\t\tthis._registerGuardFromDescriptor(descriptor, exports[i].fn);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresolve(exports[0].fn(context));\n\t\t\t\t\t\t},\n\t\t\t\t\t\t(err: Error) => {\n\t\t\t\t\t\t\tLog.warning(\n\t\t\t\t\t\t\t\t`guardRouter.guards: lazy load of \"${modulePath}\" failed`,\n\t\t\t\t\t\t\t\tString(err),\n\t\t\t\t\t\t\t\tLOG_COMPONENT,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treject(err);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t};\n\t\t\tthis._registerGuardFromDescriptor(descriptor, lazyExpander);\n\t\t}\n\t}\n\n\t/**\n\t * Clean up guards on destroy. Bumps generation to discard pending async results.\n\t *\n\t * @since 1.0.1\n\t */\n\toverride destroy(): this {\n\t\tthis._destroyed = true;\n\t\tthis._pipeline.clear();\n\t\tthis._pendingGuardDescriptors = [];\n\t\tthis._sourceDescriptors = [];\n\t\tthis._cancelPendingNavigation();\n\t\tthis._suppressedHash = null;\n\t\tthis._lastSettlement = null;\n\t\tthis._manifestMeta.clear();\n\t\tthis._runtimeMeta.clear();\n\t\tthis._resolvedMetaCache.clear();\n\t\tsuper.destroy();\n\t\treturn this;\n\t}\n}\n"],"mappings":"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","ignoreList":[],"sourceRoot":""}},{"offset":{"line":4,"column":0},"map":{"version":3,"names":["NavigationOutcome","_interopRequireDefault","__NavigationOutcome","library","Lib","init","apiVersion","name","version","dependencies","types","interfaces","controls","elements","noLibraryCSS","DataType","registerEnum"],"sources":["library.ts"],"sourcesContent":["import Lib from \"sap/ui/core/Lib\";\nimport DataType from \"sap/ui/base/DataType\";\nimport \"sap/ui/core/library\";\nimport \"sap/m/library\";\nimport NavigationOutcome from \"./NavigationOutcome\";\n\nconst library = Lib.init({\n\tapiVersion: 2,\n\tname: \"ui5.guard.router\",\n\tversion: \"1.6.1\",\n\tdependencies: [\"sap.ui.core\", \"sap.m\"],\n\ttypes: [\"ui5.guard.router.NavigationOutcome\"],\n\tinterfaces: [],\n\tcontrols: [],\n\telements: [],\n\tnoLibraryCSS: true,\n});\n\nDataType.registerEnum(\"ui5.guard.router.NavigationOutcome\", NavigationOutcome);\n\nexport default library;\n"],"mappings":"AAAA,4QAIOA,EAAiBC,EAAAC,GAExB,MAAMC,EAAUC,EAAIC,KAAK,CACxBC,WAAY,EACZC,KAAM,mBACNC,QAAS,QACTC,aAAc,CAAC,cAAe,SAC9BC,MAAO,CAAC,sCACRC,WAAY,GACZC,SAAU,GACVC,SAAU,GACVC,aAAc,OAGfC,EAASC,aAAa,qCAAsChB,GAAmB,OAEhEG,CAAO","ignoreList":[],"sourceRoot":""}},{"offset":{"line":5,"column":0},"map":{"version":3,"names":[],"sources":["library-preload.js?bundle-code-0"],"mappings":"AAAA;AACA","sourcesContent":["sap.ui.require.preload({\n"],"sourceRoot":""}},{"offset":{"line":8,"column":0},"map":{"version":3,"file":"types.js","names":[],"sources":[],"mappings":"","ignoreList":[],"sourceRoot":""}}]}
@@ -1,2 +1,2 @@
1
- sap.ui.define(["sap/ui/core/Lib","sap/ui/base/DataType","sap/ui/core/library","sap/m/library","./NavigationOutcome"],function(e,i,r,t,u){"use strict";function a(e){return e&&e.__esModule&&typeof e.default!=="undefined"?e.default:e}const n=a(u);const o=e.init({apiVersion:2,name:"ui5.guard.router",version:"1.6.0",dependencies:["sap.ui.core","sap.m"],types:["ui5.guard.router.NavigationOutcome"],interfaces:[],controls:[],elements:[],noLibraryCSS:true});i.registerEnum("ui5.guard.router.NavigationOutcome",n);return o});
1
+ sap.ui.define(["sap/ui/core/Lib","sap/ui/base/DataType","sap/ui/core/library","sap/m/library","./NavigationOutcome"],function(e,i,r,t,u){"use strict";function a(e){return e&&e.__esModule&&typeof e.default!=="undefined"?e.default:e}const n=a(u);const o=e.init({apiVersion:2,name:"ui5.guard.router",version:"1.6.1",dependencies:["sap.ui.core","sap.m"],types:["ui5.guard.router.NavigationOutcome"],interfaces:[],controls:[],elements:[],noLibraryCSS:true});i.registerEnum("ui5.guard.router.NavigationOutcome",n);return o});
2
2
  //# sourceMappingURL=library.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"library.js","names":["NavigationOutcome","_interopRequireDefault","__NavigationOutcome","library","Lib","init","apiVersion","name","version","dependencies","types","interfaces","controls","elements","noLibraryCSS","DataType","registerEnum"],"sources":["library.ts"],"sourcesContent":["import Lib from \"sap/ui/core/Lib\";\nimport DataType from \"sap/ui/base/DataType\";\nimport \"sap/ui/core/library\";\nimport \"sap/m/library\";\nimport NavigationOutcome from \"./NavigationOutcome\";\n\nconst library = Lib.init({\n\tapiVersion: 2,\n\tname: \"ui5.guard.router\",\n\tversion: \"1.6.0\",\n\tdependencies: [\"sap.ui.core\", \"sap.m\"],\n\ttypes: [\"ui5.guard.router.NavigationOutcome\"],\n\tinterfaces: [],\n\tcontrols: [],\n\telements: [],\n\tnoLibraryCSS: true,\n});\n\nDataType.registerEnum(\"ui5.guard.router.NavigationOutcome\", NavigationOutcome);\n\nexport default library;\n"],"mappings":"6OAIOA,EAAiBC,EAAAC,GAExB,MAAMC,EAAUC,EAAIC,KAAK,CACxBC,WAAY,EACZC,KAAM,mBACNC,QAAS,QACTC,aAAc,CAAC,cAAe,SAC9BC,MAAO,CAAC,sCACRC,WAAY,GACZC,SAAU,GACVC,SAAU,GACVC,aAAc,OAGfC,EAASC,aAAa,qCAAsChB,GAAmB,OAEhEG,CAAO","ignoreList":[]}
1
+ {"version":3,"file":"library.js","names":["NavigationOutcome","_interopRequireDefault","__NavigationOutcome","library","Lib","init","apiVersion","name","version","dependencies","types","interfaces","controls","elements","noLibraryCSS","DataType","registerEnum"],"sources":["library.ts"],"sourcesContent":["import Lib from \"sap/ui/core/Lib\";\nimport DataType from \"sap/ui/base/DataType\";\nimport \"sap/ui/core/library\";\nimport \"sap/m/library\";\nimport NavigationOutcome from \"./NavigationOutcome\";\n\nconst library = Lib.init({\n\tapiVersion: 2,\n\tname: \"ui5.guard.router\",\n\tversion: \"1.6.1\",\n\tdependencies: [\"sap.ui.core\", \"sap.m\"],\n\ttypes: [\"ui5.guard.router.NavigationOutcome\"],\n\tinterfaces: [],\n\tcontrols: [],\n\telements: [],\n\tnoLibraryCSS: true,\n});\n\nDataType.registerEnum(\"ui5.guard.router.NavigationOutcome\", NavigationOutcome);\n\nexport default library;\n"],"mappings":"6OAIOA,EAAiBC,EAAAC,GAExB,MAAMC,EAAUC,EAAIC,KAAK,CACxBC,WAAY,EACZC,KAAM,mBACNC,QAAS,QACTC,aAAc,CAAC,cAAe,SAC9BC,MAAO,CAAC,sCACRC,WAAY,GACZC,SAAU,GACVC,SAAU,GACVC,aAAc,OAGfC,EAASC,aAAa,qCAAsChB,GAAmB,OAEhEG,CAAO","ignoreList":[]}
@@ -4,7 +4,7 @@
4
4
  "id": "ui5.guard.router",
5
5
  "type": "library",
6
6
  "applicationVersion": {
7
- "version": "1.6.0"
7
+ "version": "1.6.1"
8
8
  },
9
9
  "title": "UI5 Router extension with async navigation guards",
10
10
  "description": "Extends sap.m.routing.Router with async navigation guards, running before route matching begins."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ui5-lib-guard-router",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "license": "MIT",
5
5
  "main": "dist/resources/ui5/guard/router/library.js",
6
6
  "types": "dist/index.d.ts",
@@ -235,7 +235,7 @@ export default class GuardPipeline {
235
235
  } catch (error) {
236
236
  Log.error(
237
237
  `Leave guard [${i}] on route "${context.fromRoute}" threw, navigation failed`,
238
- String(error),
238
+ error instanceof Error ? error : String(error),
239
239
  LOG_COMPONENT,
240
240
  );
241
241
  if (context.signal.aborted) return false;
@@ -293,7 +293,7 @@ export default class GuardPipeline {
293
293
  } catch (error) {
294
294
  Log.error(
295
295
  `Enter guard [${i}] on route "${context.toRoute}" threw, navigation failed`,
296
- String(error),
296
+ error instanceof Error ? error : String(error),
297
297
  LOG_COMPONENT,
298
298
  );
299
299
  if (context.signal.aborted) return false;
@@ -338,7 +338,7 @@ export default class GuardPipeline {
338
338
  const route = isLeaveGuard ? context.fromRoute : context.toRoute;
339
339
  Log.error(
340
340
  `${label} [${guardIndex}] on route "${route}" threw, navigation failed`,
341
- String(error),
341
+ error instanceof Error ? error : String(error),
342
342
  LOG_COMPONENT,
343
343
  );
344
344
  throw error;
package/src/manifest.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "id": "ui5.guard.router",
5
5
  "type": "library",
6
6
  "applicationVersion": {
7
- "version": "1.6.0"
7
+ "version": "1.6.1"
8
8
  },
9
9
  "title": "UI5 Router extension with async navigation guards",
10
10
  "description": "Extends sap.m.routing.Router with async navigation guards, running before route matching begins."