@typed/router 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/Link.d.ts +26 -11
  2. package/dist/Link.d.ts.map +1 -1
  3. package/dist/Link.js +47 -23
  4. package/dist/Link.js.map +1 -1
  5. package/dist/Match.d.ts +33 -0
  6. package/dist/Match.d.ts.map +1 -0
  7. package/dist/Match.js +16 -0
  8. package/dist/Match.js.map +1 -0
  9. package/dist/Matcher.d.ts +28 -0
  10. package/dist/Matcher.d.ts.map +1 -0
  11. package/dist/Matcher.js +24 -0
  12. package/dist/Matcher.js.map +1 -0
  13. package/dist/Navigation.d.ts +10 -0
  14. package/dist/Navigation.d.ts.map +1 -0
  15. package/dist/Navigation.js +7 -0
  16. package/dist/Navigation.js.map +1 -0
  17. package/dist/Redirect.d.ts +27 -0
  18. package/dist/Redirect.d.ts.map +1 -0
  19. package/dist/Redirect.js +17 -0
  20. package/dist/Redirect.js.map +1 -0
  21. package/dist/RouteOutlet.d.ts +3 -0
  22. package/dist/RouteOutlet.d.ts.map +1 -0
  23. package/dist/RouteOutlet.js +2 -0
  24. package/dist/RouteOutlet.js.map +1 -0
  25. package/dist/ScrollRestoration.d.ts +19 -0
  26. package/dist/ScrollRestoration.d.ts.map +1 -0
  27. package/dist/ScrollRestoration.js +64 -0
  28. package/dist/ScrollRestoration.js.map +1 -0
  29. package/dist/cjs/Link.d.ts +26 -11
  30. package/dist/cjs/Link.d.ts.map +1 -1
  31. package/dist/cjs/Link.js +47 -22
  32. package/dist/cjs/Link.js.map +1 -1
  33. package/dist/cjs/Match.d.ts +33 -0
  34. package/dist/cjs/Match.d.ts.map +1 -0
  35. package/dist/cjs/Match.js +43 -0
  36. package/dist/cjs/Match.js.map +1 -0
  37. package/dist/cjs/Matcher.d.ts +28 -0
  38. package/dist/cjs/Matcher.d.ts.map +1 -0
  39. package/dist/cjs/Matcher.js +52 -0
  40. package/dist/cjs/Matcher.js.map +1 -0
  41. package/dist/cjs/Navigation.d.ts +10 -0
  42. package/dist/cjs/Navigation.d.ts.map +1 -0
  43. package/dist/cjs/Navigation.js +34 -0
  44. package/dist/cjs/Navigation.js.map +1 -0
  45. package/dist/cjs/Redirect.d.ts +27 -0
  46. package/dist/cjs/Redirect.d.ts.map +1 -0
  47. package/dist/cjs/Redirect.js +44 -0
  48. package/dist/cjs/Redirect.js.map +1 -0
  49. package/dist/cjs/ScrollRestoration.d.ts +19 -0
  50. package/dist/cjs/ScrollRestoration.d.ts.map +1 -0
  51. package/dist/cjs/ScrollRestoration.js +91 -0
  52. package/dist/cjs/ScrollRestoration.js.map +1 -0
  53. package/dist/cjs/index.d.ts +7 -3
  54. package/dist/cjs/index.d.ts.map +1 -1
  55. package/dist/cjs/index.js +7 -3
  56. package/dist/cjs/index.js.map +1 -1
  57. package/dist/cjs/matchRoutes.d.ts +8 -0
  58. package/dist/cjs/matchRoutes.d.ts.map +1 -0
  59. package/dist/cjs/matchRoutes.js +77 -0
  60. package/dist/cjs/matchRoutes.js.map +1 -0
  61. package/dist/cjs/router.d.ts +24 -63
  62. package/dist/cjs/router.d.ts.map +1 -1
  63. package/dist/cjs/router.js +22 -159
  64. package/dist/cjs/router.js.map +1 -1
  65. package/dist/index.d.ts +7 -3
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +7 -3
  68. package/dist/index.js.map +1 -1
  69. package/dist/matchRoutes.d.ts +8 -0
  70. package/dist/matchRoutes.d.ts.map +1 -0
  71. package/dist/matchRoutes.js +50 -0
  72. package/dist/matchRoutes.js.map +1 -0
  73. package/dist/router.d.ts +24 -63
  74. package/dist/router.d.ts.map +1 -1
  75. package/dist/router.js +19 -153
  76. package/dist/router.js.map +1 -1
  77. package/dist/tsconfig.cjs.build.tsbuildinfo +1 -1
  78. package/package.json +12 -10
  79. package/project.json +12 -10
  80. package/src/Link.ts +129 -39
  81. package/src/Match.ts +114 -0
  82. package/src/Matcher.ts +139 -0
  83. package/src/Navigation.ts +24 -0
  84. package/src/Redirect.ts +21 -0
  85. package/src/ScrollRestoration.ts +110 -0
  86. package/src/index.ts +7 -3
  87. package/src/matchRoutes.ts +112 -0
  88. package/src/router.ts +56 -311
  89. package/tsconfig.build.json +5 -1
  90. package/tsconfig.build.tsbuildinfo +1 -1
  91. package/tsconfig.cjs.build.json +6 -0
  92. package/tsconfig.json +6 -0
  93. package/vite.config.js +3 -0
  94. package/src/RouteMatch.ts +0 -56
  95. package/src/RouteMatcher.ts +0 -264
@@ -0,0 +1,112 @@
1
+ import { identity, pipe } from '@effect/data/Function'
2
+ import * as Option from '@effect/data/Option'
3
+ import * as Effect from '@effect/io/Effect'
4
+ import * as Scope from '@effect/io/Scope'
5
+ import * as Fx from '@typed/fx'
6
+ import { RenderContext } from '@typed/html'
7
+ import { NavigationError } from '@typed/navigation'
8
+ import { ParamsOf } from '@typed/path'
9
+
10
+ import { Match } from './Match.js'
11
+ import { Redirect } from './Redirect.js'
12
+ import { Router, getCurrentPathFromUrl } from './router.js'
13
+
14
+ export function matchRoutes<
15
+ const Matches extends ReadonlyArray<Match.Any>,
16
+ R = never,
17
+ E = never,
18
+ A = never,
19
+ >(
20
+ matches: Matches,
21
+ onNotFound: (
22
+ params: Fx.Filtered<never, never, Readonly<Record<string, string>>>,
23
+ ) => Fx.Fx<R, E, A> = () => Fx.empty(),
24
+ ): Fx.Fx<
25
+ Router | RenderContext | Scope.Scope | R | Match.Context<Matches[number]>,
26
+ Exclude<E | Match.Error<Matches[number]>, Redirect>,
27
+ A | Match.Success<Matches[number]>
28
+ > {
29
+ type _R = R | Match.Context<Matches[number]> | RenderContext | Router | Scope.Scope
30
+ type _E = E | Match.Error<Matches[number]> | Redirect
31
+ type _A = A | Match.Success<Matches[number]>
32
+
33
+ type RENDERABLE = Fx.Fx<_R, _E, _A>
34
+
35
+ return Fx.gen(function* ($) {
36
+ const { environment } = yield* $(RenderContext)
37
+ const isBrowser = environment === 'browser'
38
+ const router = yield* $(Router)
39
+ const notFound = onNotFound(router.params) as RENDERABLE
40
+ const matchers = matches.map((match) => {
41
+ const nestedRouter = router.define(match.route)
42
+ const render = pipe(
43
+ nestedRouter.params,
44
+ match.render,
45
+ Fx.provideService(Router, nestedRouter as Router),
46
+ Fx.scoped,
47
+ ) as RENDERABLE
48
+
49
+ return [
50
+ match.route,
51
+ render,
52
+ match.options?.guard as
53
+ | ((params: ParamsOf<string>) => Effect.Effect<_R, NavigationError, boolean>)
54
+ | undefined,
55
+ match.options?.onMatch as
56
+ | ((params: ParamsOf<string>) => Effect.Effect<_R, _E, unknown>)
57
+ | undefined,
58
+ ] as const
59
+ })
60
+ const length = matchers.length
61
+
62
+ const matched = yield* $(
63
+ Fx.makeRef<never, any, RENDERABLE>(Effect.succeed<RENDERABLE>(Fx.empty())),
64
+ )
65
+
66
+ const matchPath = (path: string) =>
67
+ Effect.gen(function* ($) {
68
+ for (let i = 0; i < length; ++i) {
69
+ const [route, render, guard, onMatch] = matchers[i]
70
+ const params = route.match(path)
71
+
72
+ if (Option.isSome(params)) {
73
+ // If there is a guard and it fails, continue to next route
74
+ if (guard && !(yield* $(guard(params.value)))) {
75
+ continue
76
+ }
77
+
78
+ // If there is an onMatch handler, run it and catch any errors
79
+ // This is useful when you want to add tracking when a route is matched
80
+ if (onMatch) {
81
+ yield* $(
82
+ onMatch(params.value),
83
+ Effect.catchAllCause((cause) => matched.error(cause)),
84
+ Effect.forkScoped,
85
+ )
86
+ }
87
+
88
+ return yield* $(matched.set(render))
89
+ }
90
+ }
91
+
92
+ return yield* $(matched.set(notFound))
93
+ })
94
+
95
+ // Match a Route when navigation occurs
96
+ yield* $(
97
+ router.navigation.onNavigation((event) =>
98
+ matchPath(getCurrentPathFromUrl(event.destination.url)),
99
+ ),
100
+ )
101
+
102
+ return pipe(
103
+ matched,
104
+ isBrowser ? identity : Fx.take(1),
105
+ Redirect.switchMatch(
106
+ (r) => Fx.as(Fx.fromEffect(router.navigation.navigate(r.url, r.options)), Option.none()),
107
+ Fx.map(Option.some),
108
+ ),
109
+ Fx.compact,
110
+ )
111
+ })
112
+ }
package/src/router.ts CHANGED
@@ -1,338 +1,83 @@
1
- /* eslint-disable @typescript-eslint/ban-types */
2
- import { pipe } from '@effect/data/Function'
3
1
  import * as Option from '@effect/data/Option'
4
2
  import * as Effect from '@effect/io/Effect'
5
- import type * as Layer from '@effect/io/Layer'
6
- import * as Runtime from '@effect/io/Runtime'
7
- import type * as Scope from '@effect/io/Scope'
8
- import * as Context from '@typed/context'
9
- import { Document, Location, History, addWindowListener } from '@typed/dom'
10
- import * as Fx from '@typed/fx'
11
- import type * as html from '@typed/html'
12
- import { RenderContext } from '@typed/html'
13
- import * as Path from '@typed/path'
14
- import * as Route from '@typed/route'
15
-
16
- export interface Router<out R = never, out E = never, in out P extends string = string> {
17
- /**
18
- * The base route the Router is starting from.
19
- */
20
- readonly route: Route.Route<R, E, P>
21
-
22
- /**
23
- * The current path of the application
24
- */
25
- readonly currentPath: Fx.RefSubject<never, string>
26
-
27
- /**
28
- * The current matched params of the router
29
- */
30
- readonly params: Fx.Fx<R, E, Path.ParamsOf<P>>
31
-
3
+ import * as Layer from '@effect/io/Layer'
4
+ import { Tag } from '@typed/context'
5
+ import { GlobalThis, Window, DomServices, domServices, localStorage } from '@typed/dom'
6
+ import { Filtered } from '@typed/fx'
7
+ import * as Navigation from '@typed/navigation'
8
+ import { ParamsOf, PathJoin } from '@typed/path'
9
+ import { Route } from '@typed/route'
10
+
11
+ export interface Router<in out P extends string = string> {
32
12
  /**
33
- * The current outlet of this Router
13
+ * The base Route for this Router instance.
34
14
  */
35
- readonly outlet: Fx.RefSubject<Redirect, html.Renderable>
15
+ readonly route: Route<P>
36
16
 
37
17
  /**
38
- * Helper for constructing a path from a route relative to the router.
18
+ * The current params for the current path.
39
19
  */
40
- readonly createPath: <R2 extends Route.Route<any, any, string>, P extends Route.ParamsOf<R2>>(
41
- route: R2,
42
- ...[params]: [keyof P] extends [never] ? [] : [P]
43
- ) => Effect.Effect<
44
- R,
45
- never,
46
- Path.PathJoin<
47
- [Path.Interpolate<Route.PathOf<R>, Route.ParamsOf<R>>, Path.Interpolate<Route.PathOf<R2>, P>]
48
- >
49
- >
20
+ readonly params: Filtered<never, never, ParamsOf<P>>
50
21
 
51
22
  /**
52
- * Helper for constructing a nested router
23
+ * Construct a new Router instance by defining a new Route which is concatenated
24
+ * to the current Route.
53
25
  */
54
- readonly define: <R2, E2, Path2 extends string>(
55
- route: Route.Route<R2, E2, Path2>,
56
- ) => Router<R | R2, E | E2, Path.PathJoin<[P, Path2]>>
26
+ readonly define: <P2 extends string>(route: Route<P2>) => Router<PathJoin<[P, P2]>>
57
27
 
58
28
  /**
59
- * The parent router if one exists
29
+ * The parent Router instance if one exists.
60
30
  */
61
- readonly parent: Option.Option<Router<any, string>>
31
+ readonly parent: Option.Option<Router<string>>
62
32
 
63
33
  /**
64
- * Provide all the resources needed for a Router
34
+ * The Navigation Service
65
35
  */
66
- readonly provideContext: (environment: Context.Context<R>) => Router<never, E, P>
67
- }
68
-
69
- export const Router = Object.assign(Context.Tag<Router>('@typed/router/Router'), {
70
- make: function makeRouter<R = never, E = never, P extends string = string>(
71
- route: Route.Route<R, E, P>,
72
- currentPath: Fx.RefSubject<never, string>,
73
- parent: Option.Option<Router<any, any, string>> = Option.none(),
74
- ): Router<R, E, P> {
75
- const outlet = Fx.RefSubject.unsafeMake<Redirect, html.Renderable>(
76
- Effect.sync((): html.Renderable => null),
77
- )
78
-
79
- const createPath = <R2 extends Route.Route<any, any, string>, P extends Route.ParamsOf<R2>>(
80
- other: R2,
81
- ...[params]: [keyof P] extends [never] ? [] : [P]
82
- ): Effect.Effect<
83
- R,
84
- E,
85
- Path.PathJoin<
86
- [
87
- Path.Interpolate<Route.PathOf<R>, Route.ParamsOf<R>>,
88
- Path.Interpolate<Route.PathOf<R2>, P>,
89
- ]
90
- >
91
- > =>
92
- Effect.gen(function* ($) {
93
- const path = yield* $(currentPath.get)
94
- const baseParams = yield* $(route.match(path))
95
-
96
- if (Option.isNone(baseParams)) {
97
- return yield* $(
98
- Effect.dieMessage(
99
- `Can not create path when the parent can not be matched.
100
- Parent Route: ${route.path}
101
- Current Route: ${other.path}
102
- Current Path: ${path}`,
103
- ),
104
- )
105
- }
106
-
107
- return route.concat(other).make({ ...baseParams.value, ...params } as any) as any
108
- })
109
-
110
- const router: Router<R, E, P> = {
111
- route,
112
- currentPath,
113
- params: pipe(currentPath, Fx.switchMapEffect(route.match), Fx.compact, Fx.hold),
114
- outlet,
115
- createPath: createPath as Router<R, P>['createPath'],
116
- define: <R2, E2, Path2 extends string>(other: Route.Route<R2, E2, Path2>) =>
117
- makeRouter(route.concat(other), currentPath, Option.some(router as any)) as any,
118
- provideContext: (env) => provideContext(env)(router),
119
- parent,
120
- }
121
-
122
- return router
123
- },
124
- })
125
-
126
- export const outlet: Fx.Fx<RenderContext | Router, Redirect, html.Renderable> =
127
- RenderContext.withFx(({ environment }) =>
128
- Router.withFx((r) =>
129
- environment === 'browser'
130
- ? r.outlet
131
- : pipe(
132
- r.outlet,
133
- Fx.skipUntil((x) => x !== null),
134
- Fx.take(1),
135
- ),
136
- ),
137
- )
138
-
139
- export const currentPath: Fx.Fx<Router, never, string> = Router.withFx((r) => r.currentPath)
140
-
141
- export function provideContext<R>(environment: Context.Context<R>) {
142
- return <E, P extends string>(router: Router<R, E, P>): Router<never, E, P> => {
143
- const provided: Router<never, E, P> = {
144
- ...router,
145
- params: pipe(router.params, Fx.provideContext(environment)),
146
- route: Route.provideContext(environment)(router.route),
147
- createPath: ((other, ...params) =>
148
- Effect.provideContext<R>(environment)(router.createPath(other, ...params))) as Router<
149
- never,
150
- P
151
- >['createPath'],
152
- provideContext: (env) => provideContext(env)(provided),
153
- }
154
-
155
- return provided
156
- }
157
- }
158
-
159
- export interface Redirect {
160
- readonly _tag: 'Redirect'
161
- readonly path: string
162
- }
163
-
164
- export namespace Redirect {
165
- export const make = (path: string): Redirect => ({ _tag: 'Redirect', path })
166
-
167
- export const is = (r: unknown): r is Redirect =>
168
- typeof r === 'object' && r !== null && '_tag' in r && r._tag === 'Redirect'
169
- }
170
-
171
- export function redirect(path: string) {
172
- return Effect.fail<Redirect>(Redirect.make(path))
36
+ readonly navigation: Navigation.Navigation
173
37
  }
174
38
 
175
- redirect.fx = (path: string): Fx.Fx<never, Redirect, never> =>
176
- Fx.fail<Redirect>(Redirect.make(path))
177
-
178
- export const redirectTo = <R, E, P extends string>(
179
- route: Route.Route<R, E, P>,
180
- ...[params]: [keyof Path.ParamsOf<P>] extends [never] ? [{}?] : [Path.ParamsOf<P>]
181
- ): Effect.Effect<Router, Redirect, never> =>
182
- pipe(
183
- Router.withEffect((r) => r.createPath(route as any, params as any)),
184
- Effect.flatMap(redirect),
185
- )
186
-
187
- redirectTo.fx = <R, E, P extends string>(
188
- route: Route.Route<R, E, P>,
189
- ...params: [keyof Path.ParamsOf<P>] extends [never] ? [{}?] : [(path: string) => Path.ParamsOf<P>]
190
- ): Fx.Fx<Router, Redirect, never> =>
191
- pipe(
192
- Router.withEffect((r) => r.createPath(route as any, params as any)),
193
- Fx.fromEffect,
194
- Fx.switchMap(redirect.fx),
195
- )
196
-
197
- // TOOD: Add support for reading <base> tag for default Router path.
39
+ export const Router = Tag<Router>('Router')
198
40
 
199
- export const makeRouter = (
200
- currentPath?: Fx.RefSubject<never, string>,
201
- ): Effect.Effect<Location | History | Window | Document | Scope.Scope, never, Router> =>
41
+ export const navigation: Layer.Layer<Navigation.Navigation, never, Router> = Router.layer(
202
42
  Effect.gen(function* ($) {
203
- const history = yield* $(History)
204
- const location = yield* $(Location)
205
-
206
- if (!currentPath) {
207
- currentPath = Fx.RefSubject.unsafeMake(
208
- Effect.sync(() => getCurrentPathFromLocation(location)),
209
- )
210
- }
211
-
212
- // Patch history events to emit an event when the path changes
213
- const historyEvents = yield* $(patchHistory)
214
-
215
- // Update the current path when events occur:
216
- // - popstate
217
- // - hashchange
218
- // - history events
219
- yield* $(
220
- Fx.mergeAll(addWindowListener('popstate'), addWindowListener('hashchange'), historyEvents),
221
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
222
- Fx.switchMapEffect(() => currentPath!.set(getCurrentPathFromLocation(location))),
223
- Fx.drain,
224
- Effect.forkScoped,
225
- )
226
-
227
- // Listen to path changes and update the current history location, if necessary
228
- yield* $(
229
- pipe(
230
- currentPath,
231
- Fx.skipRepeats,
232
- Fx.observe((path) =>
233
- Effect.sync(() => {
234
- if (path !== getCurrentPathFromLocation(location)) {
235
- history.pushState({}, '', path)
236
- }
237
- }),
238
- ),
239
- Effect.forkScoped,
240
- ),
43
+ const navigation = yield* $(Navigation.Navigation)
44
+ const currentPath = navigation.currentEntry.map((destination) =>
45
+ getCurrentPathFromUrl(destination.url),
241
46
  )
242
47
 
243
- // Find the configured base path
244
- const document = yield* $(Document)
245
- const base = document.querySelector('base')
246
- const baseHref = base ? getBasePathFromHref(base.href) : '/'
247
-
248
- // Make our base router
249
- return Router.make(Route.Route(baseHref), currentPath) as Router
250
- })
251
-
252
- export const live = (
253
- currentPath?: Fx.RefSubject<never, string>,
254
- ): Layer.Layer<Location | History | Window | Document, never, Router<never, never, string>> =>
255
- Router.layerScoped(makeRouter(currentPath))
256
-
257
- export function getCurrentPathFromLocation(location: Location | HTMLAnchorElement | URL) {
258
- return location.pathname + location.search + location.hash
259
- }
260
-
261
- export const getCurrentPath = Router.withEffect((r) => r.currentPath.get)
262
-
263
- export const getBasePath = Router.with((r) => {
264
- const routers: Router<any, any>[] = [r]
265
- let current: Router<any, any> = r
266
-
267
- while (Option.isSome(current.parent)) {
268
- current = current.parent.value
269
- routers.push(current)
270
- }
271
-
272
- return routers.reduceRight((acc, r) => Path.pathJoin(r.route.path, acc), '')
273
- })
274
-
275
- const patchHistory = Effect.gen(function* ($) {
276
- const history = yield* $(History)
277
- const historyEvents = Fx.makeSubject<never, void>()
278
- const runtime = yield* $(Effect.runtime<never>())
279
- const runFork = Runtime.runFork(runtime)
280
- const cleanup = patchHistory_(history, () => runFork(historyEvents.event()))
281
-
282
- // unpatch history upon finalization
283
- yield* $(Effect.addFinalizer(() => Effect.sync(cleanup)))
284
-
285
- return historyEvents
286
- })
287
-
288
- function patchHistory_(history: History, sendEvent: () => void) {
289
- const pushState = history.pushState.bind(history)
290
- const replaceState = history.replaceState.bind(history)
291
- const go = history.go.bind(history)
292
- const back = history.back.bind(history)
293
- const forward = history.forward.bind(history)
294
-
295
- history.pushState = function (state, title, url) {
296
- pushState(state, title, url)
297
- sendEvent()
298
- }
299
-
300
- history.replaceState = function (state, title, url) {
301
- replaceState(state, title, url)
302
- sendEvent()
303
- }
304
-
305
- history.go = function (delta) {
306
- go(delta)
307
- sendEvent()
308
- }
309
-
310
- history.back = function () {
311
- back()
312
- sendEvent()
313
- }
48
+ function makeRouter<P extends string>(
49
+ route: Route<P>,
50
+ parent: Option.Option<Router<any>>,
51
+ ): Router<P> {
52
+ const router: Router<P> = {
53
+ route,
54
+ navigation,
55
+ params: currentPath.filterMap(route.match),
56
+ define: <P2 extends string>(other: Route<P2>): Router<PathJoin<[P, P2]>> =>
57
+ makeRouter(route.concat(other), Option.some(router)),
58
+ parent,
59
+ }
60
+
61
+ return router
62
+ }
314
63
 
315
- history.forward = function () {
316
- forward()
317
- sendEvent()
318
- }
64
+ return makeRouter(Route(navigation.base), Option.none())
65
+ }),
66
+ )
319
67
 
320
- // Reset history to original state
321
- return () => {
322
- history.pushState = pushState
323
- history.replaceState = replaceState
324
- history.go = go
325
- history.back = back
326
- history.forward = forward
327
- }
68
+ export function getCurrentPathFromUrl(url: URL): string {
69
+ return url.pathname + url.search + url.hash
328
70
  }
329
71
 
330
- function getBasePathFromHref(href: string) {
331
- try {
332
- const url = new URL(href)
72
+ export const dom = (
73
+ options?: Navigation.DomNavigationOptions,
74
+ ): Layer.Layer<GlobalThis | Window, never, DomServices | Navigation.Navigation | Router> =>
75
+ Layer.provideMerge(
76
+ localStorage,
77
+ Layer.provideMerge(domServices, Layer.provideMerge(Navigation.dom(options), navigation)),
78
+ )
333
79
 
334
- return getCurrentPathFromLocation(url)
335
- } catch {
336
- return href
337
- }
338
- }
80
+ export const memory = (
81
+ options: Navigation.MemoryNavigationOptions,
82
+ ): Layer.Layer<never, never, Navigation.Navigation | Router> =>
83
+ Layer.provideMerge(Navigation.memory(options), navigation)
@@ -1,4 +1,8 @@
1
1
  {
2
2
  "extends": "./tsconfig.json",
3
- "exclude": ["src/**/*.test.ts"]
3
+ "exclude": [
4
+ "src/**/*.test.ts",
5
+ "src/**/*.test-d.ts",
6
+ "dist"
7
+ ]
4
8
  }