@typed/navigation 0.10.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Navigation.ts CHANGED
@@ -35,45 +35,45 @@ export interface Navigation {
35
35
  readonly navigate: (
36
36
  url: string | URL,
37
37
  options?: NavigateOptions
38
- ) => Effect.Effect<never, NavigationError, Destination>
38
+ ) => Effect.Effect<Destination, NavigationError>
39
39
 
40
- readonly back: (options?: { readonly info?: unknown }) => Effect.Effect<never, NavigationError, Destination>
40
+ readonly back: (options?: { readonly info?: unknown }) => Effect.Effect<Destination, NavigationError>
41
41
 
42
- readonly forward: (options?: { readonly info?: unknown }) => Effect.Effect<never, NavigationError, Destination>
42
+ readonly forward: (options?: { readonly info?: unknown }) => Effect.Effect<Destination, NavigationError>
43
43
 
44
44
  readonly traverseTo: (
45
45
  key: Destination["key"],
46
46
  options?: { readonly info?: unknown }
47
- ) => Effect.Effect<never, NavigationError, Destination>
47
+ ) => Effect.Effect<Destination, NavigationError>
48
48
 
49
49
  readonly updateCurrentEntry: (
50
50
  options: { readonly state: unknown }
51
- ) => Effect.Effect<never, NavigationError, Destination>
51
+ ) => Effect.Effect<Destination, NavigationError>
52
52
 
53
53
  readonly reload: (
54
54
  options?: { readonly info?: unknown; readonly state?: unknown }
55
- ) => Effect.Effect<never, NavigationError, Destination>
55
+ ) => Effect.Effect<Destination, NavigationError>
56
56
 
57
57
  readonly beforeNavigation: <R = never, R2 = never>(
58
58
  handler: BeforeNavigationHandler<R, R2>
59
- ) => Effect.Effect<R | R2 | Scope.Scope, never, void>
59
+ ) => Effect.Effect<void, never, R | R2 | Scope.Scope>
60
60
 
61
61
  readonly onNavigation: <R = never, R2 = never>(
62
62
  handler: NavigationHandler<R, R2>
63
- ) => Effect.Effect<R | R2 | Scope.Scope, never, void>
63
+ ) => Effect.Effect<void, never, R | R2 | Scope.Scope>
64
64
 
65
65
  readonly submit: (
66
66
  data: FormData,
67
67
  formInput?: Simplify<Omit<FormInputFrom, "data">>
68
68
  ) => Effect.Effect<
69
- HttpClient.client.Client.Default,
69
+ Option.Option<HttpClient.response.ClientResponse>,
70
70
  NavigationError | HttpClient.error.HttpClientError,
71
- Option.Option<HttpClient.response.ClientResponse>
71
+ Scope.Scope | HttpClient.client.Client.Default
72
72
  >
73
73
 
74
74
  readonly onFormData: <R = never, R2 = never>(
75
75
  handler: FormDataHandler<R, R2>
76
- ) => Effect.Effect<R | R2 | Scope.Scope, never, void>
76
+ ) => Effect.Effect<void, never, R | R2 | Scope.Scope>
77
77
  }
78
78
 
79
79
  /**
@@ -203,11 +203,11 @@ export interface NavigationEvent extends Schema.Schema.To<typeof NavigationEvent
203
203
  export type BeforeNavigationHandler<R, R2> = (
204
204
  event: BeforeNavigationEvent
205
205
  ) => Effect.Effect<
206
- R,
207
- RedirectError | CancelNavigation,
208
206
  Option.Option<
209
- Effect.Effect<R2, RedirectError | CancelNavigation, unknown>
210
- >
207
+ Effect.Effect<unknown, RedirectError | CancelNavigation, R2>
208
+ >,
209
+ RedirectError | CancelNavigation,
210
+ R
211
211
  >
212
212
 
213
213
  /**
@@ -216,11 +216,11 @@ export type BeforeNavigationHandler<R, R2> = (
216
216
  export type NavigationHandler<R, R2> = (
217
217
  event: NavigationEvent
218
218
  ) => Effect.Effect<
219
- R,
220
- never,
221
219
  Option.Option<
222
- Effect.Effect<R2, never, unknown>
223
- >
220
+ Effect.Effect<unknown, never, R2>
221
+ >,
222
+ never,
223
+ R
224
224
  >
225
225
 
226
226
  /**
@@ -229,11 +229,11 @@ export type NavigationHandler<R, R2> = (
229
229
  export type FormDataHandler<R, R2> = (
230
230
  event: FormDataEvent
231
231
  ) => Effect.Effect<
232
- R,
233
- RedirectError | CancelNavigation,
234
232
  Option.Option<
235
- Effect.Effect<R2, RedirectError | CancelNavigation, Option.Option<HttpClient.response.ClientResponse>>
236
- >
233
+ Effect.Effect<Option.Option<HttpClient.response.ClientResponse>, RedirectError | CancelNavigation, R2>
234
+ >,
235
+ RedirectError | CancelNavigation,
236
+ R
237
237
  >
238
238
 
239
239
  /**
@@ -400,12 +400,12 @@ export function isCancelNavigation(e: unknown): e is CancelNavigation {
400
400
  export const navigate = (
401
401
  url: string | URL,
402
402
  options?: NavigateOptions
403
- ): Effect.Effect<Navigation, NavigationError, Destination> => Navigation.withEffect((n) => n.navigate(url, options))
403
+ ): Effect.Effect<Destination, NavigationError, Navigation> => Navigation.withEffect((n) => n.navigate(url, options))
404
404
 
405
405
  /**
406
406
  * @since 1.0.0
407
407
  */
408
- export const back: (options?: { readonly info?: unknown }) => Effect.Effect<Navigation, NavigationError, Destination> =
408
+ export const back: (options?: { readonly info?: unknown }) => Effect.Effect<Destination, NavigationError, Navigation> =
409
409
  (opts) => Navigation.withEffect((n) => n.back(opts))
410
410
 
411
411
  /**
@@ -413,7 +413,7 @@ export const back: (options?: { readonly info?: unknown }) => Effect.Effect<Navi
413
413
  */
414
414
  export const forward: (
415
415
  options?: { readonly info?: unknown }
416
- ) => Effect.Effect<Navigation, NavigationError, Destination> = (
416
+ ) => Effect.Effect<Destination, NavigationError, Navigation> = (
417
417
  opts
418
418
  ) => Navigation.withEffect((n) => n.forward(opts))
419
419
 
@@ -423,7 +423,7 @@ export const forward: (
423
423
  export const traverseTo: (
424
424
  key: Uuid,
425
425
  options?: { readonly info?: unknown }
426
- ) => Effect.Effect<Navigation, NavigationError, Destination> = (key, opts) =>
426
+ ) => Effect.Effect<Destination, NavigationError, Navigation> = (key, opts) =>
427
427
  Navigation.withEffect((n) => n.traverseTo(key, opts))
428
428
 
429
429
  /**
@@ -431,7 +431,7 @@ export const traverseTo: (
431
431
  */
432
432
  export const updateCurrentEntry: (
433
433
  options: { readonly state: unknown }
434
- ) => Effect.Effect<Navigation, NavigationError, Destination> = (opts) =>
434
+ ) => Effect.Effect<Destination, NavigationError, Navigation> = (opts) =>
435
435
  Navigation.withEffect((n) => n.updateCurrentEntry(opts))
436
436
 
437
437
  /**
@@ -439,7 +439,7 @@ export const updateCurrentEntry: (
439
439
  */
440
440
  export const reload: (
441
441
  options?: { readonly info?: unknown; readonly state?: unknown }
442
- ) => Effect.Effect<Navigation, NavigationError, Destination> = (
442
+ ) => Effect.Effect<Destination, NavigationError, Navigation> = (
443
443
  opts
444
444
  ) => Navigation.withEffect((n) => n.reload(opts))
445
445
 
@@ -508,9 +508,9 @@ export function submit(
508
508
  data: FormData,
509
509
  formInput?: Simplify<Omit<FormInputFrom, "data">>
510
510
  ): Effect.Effect<
511
- Navigation | HttpClient.client.Client.Default,
511
+ Option.Option<HttpClient.response.ClientResponse>,
512
512
  NavigationError | HttpClient.error.HttpClientError,
513
- Option.Option<HttpClient.response.ClientResponse>
513
+ Navigation | HttpClient.client.Client.Default | Scope.Scope
514
514
  > {
515
515
  return Navigation.withEffect((n) => n.submit(data, formInput))
516
516
  }
@@ -520,6 +520,6 @@ export function submit(
520
520
  */
521
521
  export function onFormData<R = never, R2 = never>(
522
522
  handler: FormDataHandler<R, R2>
523
- ): Effect.Effect<Navigation | R | R2 | Scope.Scope, never, void> {
523
+ ): Effect.Effect<void, never, Navigation | R | R2 | Scope.Scope> {
524
524
  return Navigation.withEffect((n) => n.onFormData(handler))
525
525
  }
@@ -38,7 +38,7 @@ declare global {
38
38
  }
39
39
  }
40
40
 
41
- export const fromWindow: Layer.Layer<Window, never, Navigation> = Navigation.scoped(
41
+ export const fromWindow: Layer.Layer<Navigation, never, Window> = Navigation.scoped(
42
42
  Window.withEffect((window) => {
43
43
  const getRandomValues = (length: number) => Effect.sync(() => window.crypto.getRandomValues(new Uint8Array(length)))
44
44
  return Effect.gen(function*(_) {
@@ -108,12 +108,8 @@ const getNavigationState = (navigation: NativeNavigation): NavigationState => {
108
108
 
109
109
  function setupWithNavigation(
110
110
  navigation: NativeNavigation,
111
- runPromise: <E, A>(effect: Effect.Effect<Scope.Scope, E, A>) => Promise<A>
112
- ): Effect.Effect<
113
- Scope.Scope | GetRandomValues,
114
- never,
115
- ModelAndIntent
116
- > {
111
+ runPromise: <E, A>(effect: Effect.Effect<A, E, Scope.Scope>) => Promise<A>
112
+ ): Effect.Effect<ModelAndIntent, never, Scope.Scope | GetRandomValues> {
117
113
  return Effect.gen(function*(_) {
118
114
  const state = yield* _(
119
115
  RefSubject.fromEffect(
@@ -150,7 +146,7 @@ function setupWithNavigation(
150
146
  const runHandlers = (native: NativeEvent) =>
151
147
  Effect.gen(function*(_) {
152
148
  const eventHandlers = yield* _(handlers)
153
- const matches: Array<Effect.Effect<never, never, unknown>> = []
149
+ const matches: Array<Effect.Effect<unknown>> = []
154
150
 
155
151
  const event: NavigationEvent = {
156
152
  type: native.navigationType,
@@ -220,11 +216,7 @@ function shouldNotIntercept(navigationEvent: NativeEvent): boolean {
220
216
  function setupWithHistory(
221
217
  window: Window,
222
218
  onEvent: (event: HistoryEvent) => void
223
- ): Effect.Effect<
224
- GetRandomValues | Scope.Scope,
225
- never,
226
- ModelAndIntent
227
- > {
219
+ ): Effect.Effect<ModelAndIntent, never, GetRandomValues | Scope.Scope> {
228
220
  return Effect.gen(function*(_) {
229
221
  const { location } = window
230
222
  const { original: history, unpatch } = patchHistory(window, onEvent)
@@ -355,11 +347,15 @@ function patchHistory(window: Window, onEvent: (event: HistoryEvent) => void) {
355
347
 
356
348
  // In a proper browser this will allow patching to hide the id/key's associated with the state
357
349
  if (stateDescriptor) {
358
- Object.defineProperty(history, "state", {
359
- get() {
360
- return getOriginalState(stateDescriptor.get!.call(history))
361
- }
362
- })
350
+ try {
351
+ Object.defineProperty(history, "state", {
352
+ get() {
353
+ return getOriginalState(stateDescriptor.get!.call(history))
354
+ }
355
+ })
356
+ } catch {
357
+ // We tried, but it didn't work
358
+ }
363
359
  }
364
360
 
365
361
  const onHashChange = (ev: HashChangeEvent) => {
@@ -386,7 +382,11 @@ function patchHistory(window: Window, onEvent: (event: HistoryEvent) => void) {
386
382
  history.forward = original.forward
387
383
 
388
384
  if (stateDescriptor) {
389
- Object.defineProperty(history, "state", stateDescriptor)
385
+ try {
386
+ Object.defineProperty(history, "state", stateDescriptor)
387
+ } catch {
388
+ // We tried, but it didn't work
389
+ }
390
390
  }
391
391
 
392
392
  window.removeEventListener("hashchange", onHashChange)
@@ -403,19 +403,15 @@ function patchHistory(window: Window, onEvent: (event: HistoryEvent) => void) {
403
403
  type ScopedRuntime<R> = {
404
404
  readonly runtime: Runtime.Runtime<R | Scope.Scope>
405
405
  readonly scope: Scope.Scope
406
- readonly run: <E, A>(effect: Effect.Effect<R | Scope.Scope, E, A>) => Fiber.RuntimeFiber<E, A>
407
- readonly runPromise: <E, A>(effect: Effect.Effect<R | Scope.Scope, E, A>) => Promise<A>
406
+ readonly run: <E, A>(effect: Effect.Effect<A, E, R | Scope.Scope>) => Fiber.RuntimeFiber<A, E>
407
+ readonly runPromise: <E, A>(effect: Effect.Effect<A, E, R | Scope.Scope>) => Promise<A>
408
408
  }
409
409
 
410
- function scopedRuntime<R>(): Effect.Effect<
411
- R | Scope.Scope,
412
- never,
413
- ScopedRuntime<R>
414
- > {
410
+ function scopedRuntime<R>(): Effect.Effect<ScopedRuntime<R>, never, R | Scope.Scope> {
415
411
  return Effect.map(Effect.runtime<R | Scope.Scope>(), (runtime) => {
416
412
  const scope = Context.get(runtime.context, Scope.Scope)
417
413
  const runFork = Runtime.runFork(runtime)
418
- const runPromise = <E, A>(effect: Effect.Effect<R | Scope.Scope, E, A>): Promise<A> =>
414
+ const runPromise = <E, A>(effect: Effect.Effect<A, E, R | Scope.Scope>): Promise<A> =>
419
415
  new Promise((resolve, reject) => {
420
416
  const fiber = runFork(effect, { scope })
421
417
  fiber.addObserver(Exit.match({
@@ -18,7 +18,7 @@ import {
18
18
  setupFromModelAndIntent
19
19
  } from "./shared.js"
20
20
 
21
- export const memory = (options: MemoryOptions): Layer.Layer<never, never, Navigation> =>
21
+ export const memory = (options: MemoryOptions): Layer.Layer<Navigation> =>
22
22
  Navigation.scoped(
23
23
  Effect.gen(function*(_) {
24
24
  const getRandomValues = yield* _(GetRandomValues)
@@ -33,7 +33,7 @@ export const memory = (options: MemoryOptions): Layer.Layer<never, never, Naviga
33
33
 
34
34
  export function initialMemory(
35
35
  options: InitialMemoryOptions
36
- ): Layer.Layer<never, never, Navigation> {
36
+ ): Layer.Layer<Navigation> {
37
37
  return Navigation.scoped(
38
38
  Effect.gen(function*(_) {
39
39
  const getRandomValues = yield* _(GetRandomValues)
@@ -56,11 +56,7 @@ export function initialMemory(
56
56
 
57
57
  function setupMemory(
58
58
  options: MemoryOptions
59
- ): Effect.Effect<
60
- GetRandomValues | Scope.Scope,
61
- never,
62
- ModelAndIntent
63
- > {
59
+ ): Effect.Effect<ModelAndIntent, never, GetRandomValues | Scope.Scope> {
64
60
  return Effect.gen(function*(_) {
65
61
  const state = yield* _(
66
62
  RefSubject.fromEffect(
@@ -92,7 +92,7 @@ export function setupFromModelAndIntent(
92
92
  const runBeforeHandlers = (event: BeforeNavigationEvent) =>
93
93
  Effect.gen(function*(_) {
94
94
  const handlers = yield* _(beforeHandlers)
95
- const matches: Array<Effect.Effect<never, RedirectError | CancelNavigation, unknown>> = []
95
+ const matches: Array<Effect.Effect<unknown, RedirectError | CancelNavigation>> = []
96
96
 
97
97
  for (const [handler, ctx] of handlers) {
98
98
  const exit = yield* _(handler(event), Effect.provide(ctx), Effect.either)
@@ -121,7 +121,7 @@ export function setupFromModelAndIntent(
121
121
  const runHandlers = (event: NavigationEvent) =>
122
122
  Effect.gen(function*(_) {
123
123
  const eventHandlers = yield* _(handlers)
124
- const matches: Array<Effect.Effect<never, never, unknown>> = []
124
+ const matches: Array<Effect.Effect<unknown>> = []
125
125
 
126
126
  for (const [handler, ctx] of eventHandlers) {
127
127
  const match = yield* _(handler(event), Effect.provide(ctx))
@@ -138,14 +138,14 @@ export function setupFromModelAndIntent(
138
138
  const runFormDataHandlers = (
139
139
  event: FormDataEvent
140
140
  ): Effect.Effect<
141
- HttpClient.client.Client.Default,
141
+ Either.Either<RedirectError | CancelNavigation, Option.Option<HttpClient.response.ClientResponse>>,
142
142
  NavigationError | HttpClient.error.HttpClientError,
143
- Either.Either<RedirectError | CancelNavigation, Option.Option<HttpClient.response.ClientResponse>>
143
+ Scope.Scope | HttpClient.client.Client.Default
144
144
  > =>
145
145
  Effect.gen(function*(_) {
146
146
  const handlers = yield* _(formDataHandlers)
147
147
  const matches: Array<
148
- Effect.Effect<never, RedirectError | CancelNavigation, Option.Option<HttpClient.response.ClientResponse>>
148
+ Effect.Effect<Option.Option<HttpClient.response.ClientResponse>, RedirectError | CancelNavigation>
149
149
  > = []
150
150
 
151
151
  for (const [handler, ctx] of handlers) {
@@ -183,11 +183,11 @@ export function setupFromModelAndIntent(
183
183
 
184
184
  const runNavigationEvent = (
185
185
  beforeEvent: BeforeNavigationEvent,
186
- get: Effect.Effect<never, never, NavigationState>,
187
- set: (a: NavigationState) => Effect.Effect<never, never, NavigationState>,
186
+ get: Effect.Effect<NavigationState>,
187
+ set: (a: NavigationState) => Effect.Effect<NavigationState>,
188
188
  depth: number,
189
189
  skipCommit: boolean = false
190
- ): Effect.Effect<never, NavigationError, Destination> =>
190
+ ): Effect.Effect<Destination, NavigationError> =>
191
191
  Effect.gen(function*(_) {
192
192
  let current = yield* _(get)
193
193
  current = yield* _(set({ ...current, transition: Option.some(beforeEvent) }))
@@ -246,10 +246,10 @@ export function setupFromModelAndIntent(
246
246
 
247
247
  const handleError = (
248
248
  error: RedirectError | CancelNavigation,
249
- get: Effect.Effect<never, never, NavigationState>,
250
- set: (a: NavigationState) => Effect.Effect<never, never, NavigationState>,
249
+ get: Effect.Effect<NavigationState>,
250
+ set: (a: NavigationState) => Effect.Effect<NavigationState>,
251
251
  depth: number
252
- ): Effect.Effect<never, NavigationError, Destination> =>
252
+ ): Effect.Effect<Destination, NavigationError> =>
253
253
  Effect.gen(function*(_) {
254
254
  if (depth >= 25) {
255
255
  return yield* _(Effect.dieMessage(`Redirect loop detected.`))
@@ -355,7 +355,7 @@ export function setupFromModelAndIntent(
355
355
 
356
356
  const beforeNavigation = <R = never, R2 = never>(
357
357
  handler: BeforeNavigationHandler<R, R2>
358
- ): Effect.Effect<R | R2 | Scope.Scope, never, void> =>
358
+ ): Effect.Effect<void, never, R | R2 | Scope.Scope> =>
359
359
  Effect.contextWithEffect((ctx) => {
360
360
  const entry = [handler, ctx] as const
361
361
 
@@ -373,7 +373,7 @@ export function setupFromModelAndIntent(
373
373
 
374
374
  const onNavigation = <R = never, R2 = never>(
375
375
  handler: NavigationHandler<R, R2>
376
- ): Effect.Effect<R | R2 | Scope.Scope, never, void> =>
376
+ ): Effect.Effect<void, never, R | R2 | Scope.Scope> =>
377
377
  Effect.contextWithEffect((ctx) => {
378
378
  const entry = [handler, ctx] as const
379
379
 
@@ -410,9 +410,9 @@ export function setupFromModelAndIntent(
410
410
  data: FormData,
411
411
  input?: Omit<FormInputFrom, "data">
412
412
  ): Effect.Effect<
413
- HttpClient.client.Client.Default,
413
+ Option.Option<HttpClient.response.ClientResponse>,
414
414
  NavigationError | HttpClient.error.HttpClientError,
415
- Option.Option<HttpClient.response.ClientResponse>
415
+ Scope.Scope | HttpClient.client.Client.Default
416
416
  > =>
417
417
  state.runUpdates(({ get, set }) =>
418
418
  Effect.gen(function*(_) {
@@ -457,7 +457,7 @@ export function setupFromModelAndIntent(
457
457
 
458
458
  const onFormData = <R = never, R2 = never>(
459
459
  handler: FormDataHandler<R, R2>
460
- ): Effect.Effect<R | R2 | Scope.Scope, never, void> =>
460
+ ): Effect.Effect<void, never, R | R2 | Scope.Scope> =>
461
461
  Effect.contextWithEffect((ctx) => {
462
462
  const entry = [handler, ctx] as const
463
463