effective-rsc 0.1.3 → 0.1.4

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.
@@ -2,24 +2,12 @@ import { Context, Effect, Layer, MutableRef } from "effect";
2
2
 
3
3
 
4
4
 
5
- const getNavigationPhase = (lifecycle, navigation)=>{
6
- const phase = lifecycle.phases.get(navigation);
7
- if (phase === undefined) {
8
- throw new TypeError('Browser navigation does not belong to this root.');
9
- }
10
- return phase;
11
- };
12
- const retireNavigation = (lifecycle, navigation)=>{
13
- if (getNavigationPhase(lifecycle, navigation) !== 'Retired') {
14
- lifecycle.phases.set(navigation, 'Retired');
15
- navigation.retired.resolve();
16
- }
17
- };
18
5
  class BrowserRenderer extends Context.Service()('ersc/client/BrowserRenderer', {
19
6
  make: Effect.sync(()=>{
20
7
  const state = MutableRef.make({
21
8
  _tag: 'Uninitialized'
22
9
  });
10
+ const publications = new WeakSet();
23
11
  const getReadyState = ()=>{
24
12
  const current = MutableRef.get(state);
25
13
  if (current._tag === 'Uninitialized') {
@@ -37,109 +25,107 @@ class BrowserRenderer extends Context.Service()('ersc/client/BrowserRenderer', {
37
25
  }
38
26
  MutableRef.set(state, {
39
27
  _tag: 'Ready',
40
- lifecycle: {
41
- active: {
42
- _tag: 'Stable'
43
- },
44
- phases: new WeakMap(),
45
- stableRouteTree: initialRouteTree,
46
- visible: {
47
- _tag: 'Stable'
48
- }
28
+ current: {
29
+ _tag: 'Initial',
30
+ routeTree: initialRouteTree
49
31
  },
32
+ publicationOrder: 0,
33
+ liveRenders: new Map(),
50
34
  publish
51
35
  });
52
36
  };
53
- const navigate = (routeTree)=>{
54
- const { lifecycle, publish } = getReadyState();
55
- const navigation = {
37
+ const publish = (render)=>{
38
+ publications.add(render);
39
+ getReadyState().publish(render);
40
+ };
41
+ const schedule = (routeTree, kind)=>{
42
+ const ready = getReadyState();
43
+ const order = ++ready.publicationOrder;
44
+ const render = {
45
+ _tag: kind,
46
+ order,
56
47
  committed: Promise.withResolvers(),
57
48
  retired: Promise.withResolvers(),
58
49
  routeTree
59
50
  };
60
- lifecycle.phases.set(navigation, 'Scheduled');
61
- lifecycle.active = {
62
- _tag: 'Navigation',
63
- navigation
64
- };
65
- publish({
66
- _tag: 'Navigation',
67
- navigation,
68
- routeTree: navigation.routeTree
51
+ ready.liveRenders.set(render, {
52
+ _tag: 'Scheduled',
53
+ lastPublicationOrder: order
69
54
  });
55
+ publish(render);
70
56
  return {
71
- committed: navigation.committed.promise,
57
+ committed: render.committed.promise,
72
58
  discard: ()=>{
73
- if (getNavigationPhase(lifecycle, navigation) !== 'Scheduled') {
74
- throw new TypeError('Only a scheduled browser navigation can be discarded.');
59
+ const live = ready.liveRenders.get(render);
60
+ // Cancellation can arrive before the caller observes a commit or retirement.
61
+ if (live?._tag !== 'Scheduled') {
62
+ return render.retired.promise;
75
63
  }
76
- lifecycle.phases.set(navigation, 'DiscardRequested');
77
- if (lifecycle.active._tag === 'Navigation' && lifecycle.active.navigation === navigation) {
78
- const visible = lifecycle.visible;
79
- lifecycle.active = visible._tag === 'Navigation' && getNavigationPhase(lifecycle, visible.navigation) === 'Visible' ? visible : {
80
- _tag: 'Stable'
81
- };
64
+ ready.liveRenders.set(render, {
65
+ _tag: 'DiscardRequested',
66
+ lastPublicationOrder: order
67
+ });
68
+ const current = ready.current;
69
+ const restore = current._tag === 'Discard' ? current.restore : current;
70
+ const discardOrder = ++ready.publicationOrder;
71
+ if (restore._tag !== 'Initial') {
72
+ // Keep the tree alive even if another render commits before this discard.
73
+ // Reinsertion keeps the map ordered by each render's last publication.
74
+ ready.liveRenders.delete(restore);
75
+ ready.liveRenders.set(restore, {
76
+ _tag: 'Committed',
77
+ lastPublicationOrder: discardOrder
78
+ });
82
79
  }
83
80
  publish({
84
81
  _tag: 'Discard',
85
- navigation,
86
- routeTree: lifecycle.visible._tag === 'Navigation' ? lifecycle.visible.navigation.routeTree : lifecycle.stableRouteTree,
87
- visible: lifecycle.visible
82
+ order: discardOrder,
83
+ restore
88
84
  });
89
- return navigation.retired.promise;
85
+ return render.retired.promise;
90
86
  },
91
- retired: navigation.retired.promise
87
+ retired: render.retired.promise
92
88
  };
93
89
  };
94
- const refresh = (routeTree)=>{
95
- const { lifecycle, publish } = getReadyState();
96
- const committed = Promise.withResolvers();
97
- lifecycle.active = {
98
- _tag: 'Stable'
99
- };
100
- publish({
101
- _tag: 'Refresh',
102
- committed,
103
- routeTree
104
- });
105
- return committed.promise;
106
- };
90
+ const navigate = (routeTree)=>schedule(routeTree, 'Navigation');
91
+ const refresh = (routeTree)=>schedule(routeTree, 'Refresh');
107
92
  const commit = (render)=>{
108
- const { lifecycle } = getReadyState();
109
- const previousVisible = lifecycle.visible;
110
- const visible = render._tag === 'Navigation' ? {
111
- _tag: 'Navigation',
112
- navigation: render.navigation
113
- } : render._tag === 'Discard' ? render.visible : {
114
- _tag: 'Stable'
115
- };
116
- lifecycle.visible = visible;
117
- if (previousVisible._tag === 'Navigation' && (visible._tag !== 'Navigation' || visible.navigation !== previousVisible.navigation)) {
118
- retireNavigation(lifecycle, previousVisible.navigation);
93
+ const ready = getReadyState();
94
+ if (render._tag === 'Initial') {
95
+ return;
119
96
  }
120
- switch(render._tag){
121
- case 'Initial':
122
- break;
123
- case 'Discard':
124
- retireNavigation(lifecycle, render.navigation);
125
- break;
126
- case 'Navigation':
127
- if (getNavigationPhase(lifecycle, render.navigation) === 'Scheduled') {
128
- lifecycle.phases.set(render.navigation, 'Visible');
129
- }
130
- if (lifecycle.active._tag === 'Navigation' && lifecycle.active.navigation === render.navigation) {
131
- lifecycle.active = {
132
- _tag: 'Stable'
133
- };
134
- lifecycle.stableRouteTree = render.routeTree;
135
- lifecycle.phases.set(render.navigation, 'Completed');
136
- }
137
- render.navigation.committed.resolve();
138
- break;
139
- case 'Refresh':
140
- lifecycle.stableRouteTree = render.routeTree;
141
- render.committed.resolve();
97
+ if (!publications.has(render)) {
98
+ throw new TypeError('Browser render does not belong to this root.');
99
+ }
100
+ const current = ready.current;
101
+ if (current._tag !== 'Initial' && render.order < current.order) {
102
+ throw new TypeError('Browser renders must commit in publication order.');
103
+ }
104
+ const visible = render._tag === 'Discard' ? render.restore : render;
105
+ if (visible._tag !== 'Initial') {
106
+ const live = ready.liveRenders.get(visible);
107
+ if (live === undefined) {
108
+ throw new TypeError('A retired browser tree cannot commit.');
109
+ }
110
+ ready.liveRenders.set(visible, {
111
+ _tag: 'Committed',
112
+ lastPublicationOrder: live.lastPublicationOrder
113
+ });
114
+ }
115
+ ready.current = render;
116
+ if (render._tag !== 'Discard') {
117
+ render.committed.resolve();
118
+ }
119
+ // A later replacement commit supersedes earlier publications. A tree stays alive
120
+ // while visible or referenced by a newer publication, including a pending discard.
121
+ for (const [retained, live] of ready.liveRenders){
122
+ if (live.lastPublicationOrder > render.order) {
142
123
  break;
124
+ }
125
+ if (retained !== visible) {
126
+ ready.liveRenders.delete(retained);
127
+ retained.retired.resolve();
128
+ }
143
129
  }
144
130
  };
145
131
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"client/browser-renderer.js","sources":["../../src/client/browser-renderer.ts"],"sourcesContent":["import { Context, Effect, Layer, MutableRef } from 'effect';\n\nimport type { RouteTreeModel } from '../rsc/route-tree';\n\nexport type BrowserRendererNavigation = {\n readonly committed: Promise<void>;\n readonly discard: () => Promise<void>;\n readonly retired: Promise<void>;\n};\n\ntype BrowserRenderNavigationState = {\n readonly committed: PromiseWithResolvers<void>;\n readonly retired: PromiseWithResolvers<void>;\n readonly routeTree: RouteTreeModel;\n};\n\ntype BrowserRenderNavigationPhase =\n | 'Scheduled'\n | 'DiscardRequested'\n | 'Visible'\n | 'Completed'\n | 'Retired';\n\ntype BrowserRenderOwner =\n | { readonly _tag: 'Stable' }\n | { readonly _tag: 'Navigation'; readonly navigation: BrowserRenderNavigationState };\n\ntype BrowserRendererLifecycle = {\n active: BrowserRenderOwner;\n readonly phases: WeakMap<BrowserRenderNavigationState, BrowserRenderNavigationPhase>;\n stableRouteTree: RouteTreeModel;\n visible: BrowserRenderOwner;\n};\n\ntype BrowserRendererState =\n | { readonly _tag: 'Uninitialized' }\n | {\n readonly _tag: 'Ready';\n readonly lifecycle: BrowserRendererLifecycle;\n readonly publish: (render: BrowserRender) => void;\n };\n\nexport type BrowserRender =\n | { readonly _tag: 'Initial'; readonly routeTree: RouteTreeModel }\n | {\n readonly _tag: 'Navigation';\n readonly navigation: BrowserRenderNavigationState;\n readonly routeTree: RouteTreeModel;\n }\n | {\n readonly _tag: 'Discard';\n readonly navigation: BrowserRenderNavigationState;\n readonly routeTree: RouteTreeModel;\n readonly visible: BrowserRenderOwner;\n }\n | {\n readonly _tag: 'Refresh';\n readonly committed: PromiseWithResolvers<void>;\n readonly routeTree: RouteTreeModel;\n };\n\nconst getNavigationPhase = (\n lifecycle: BrowserRendererLifecycle,\n navigation: BrowserRenderNavigationState,\n) => {\n const phase = lifecycle.phases.get(navigation);\n if (phase === undefined) {\n throw new TypeError('Browser navigation does not belong to this root.');\n }\n return phase;\n};\n\nconst retireNavigation = (\n lifecycle: BrowserRendererLifecycle,\n navigation: BrowserRenderNavigationState,\n) => {\n if (getNavigationPhase(lifecycle, navigation) !== 'Retired') {\n lifecycle.phases.set(navigation, 'Retired');\n navigation.retired.resolve();\n }\n};\n\nexport class BrowserRenderer extends Context.Service<BrowserRenderer>()(\n 'ersc/client/BrowserRenderer',\n {\n make: Effect.sync(() => {\n const state = MutableRef.make<BrowserRendererState>({ _tag: 'Uninitialized' });\n const getReadyState = () => {\n const current = MutableRef.get(state);\n if (current._tag === 'Uninitialized') {\n throw new TypeError('BrowserRenderer must be initialized by ReactDOMRenderer.');\n }\n return current;\n };\n\n const initialize = (\n initialRouteTree: RouteTreeModel,\n publish: (render: BrowserRender) => void,\n ) => {\n const current = MutableRef.get(state);\n if (current._tag === 'Ready') {\n if (current.publish === publish) {\n return;\n }\n throw new TypeError('BrowserRenderer cannot be initialized by more than one React root.');\n }\n\n MutableRef.set(state, {\n _tag: 'Ready',\n lifecycle: {\n active: { _tag: 'Stable' },\n phases: new WeakMap<BrowserRenderNavigationState, BrowserRenderNavigationPhase>(),\n stableRouteTree: initialRouteTree,\n visible: { _tag: 'Stable' },\n },\n publish,\n });\n };\n\n const navigate = (routeTree: RouteTreeModel) => {\n const { lifecycle, publish } = getReadyState();\n const navigation: BrowserRenderNavigationState = {\n committed: Promise.withResolvers<void>(),\n retired: Promise.withResolvers<void>(),\n routeTree,\n };\n lifecycle.phases.set(navigation, 'Scheduled');\n lifecycle.active = { _tag: 'Navigation', navigation };\n publish({ _tag: 'Navigation', navigation, routeTree: navigation.routeTree });\n\n return {\n committed: navigation.committed.promise,\n discard: () => {\n if (getNavigationPhase(lifecycle, navigation) !== 'Scheduled') {\n throw new TypeError('Only a scheduled browser navigation can be discarded.');\n }\n lifecycle.phases.set(navigation, 'DiscardRequested');\n if (\n lifecycle.active._tag === 'Navigation' &&\n lifecycle.active.navigation === navigation\n ) {\n const visible = lifecycle.visible;\n lifecycle.active =\n visible._tag === 'Navigation' &&\n getNavigationPhase(lifecycle, visible.navigation) === 'Visible'\n ? visible\n : { _tag: 'Stable' };\n }\n publish({\n _tag: 'Discard',\n navigation,\n routeTree:\n lifecycle.visible._tag === 'Navigation'\n ? lifecycle.visible.navigation.routeTree\n : lifecycle.stableRouteTree,\n visible: lifecycle.visible,\n });\n return navigation.retired.promise;\n },\n retired: navigation.retired.promise,\n };\n };\n\n const refresh = (routeTree: RouteTreeModel) => {\n const { lifecycle, publish } = getReadyState();\n const committed = Promise.withResolvers<void>();\n lifecycle.active = { _tag: 'Stable' };\n publish({ _tag: 'Refresh', committed, routeTree });\n return committed.promise;\n };\n\n const commit = (render: BrowserRender) => {\n const { lifecycle } = getReadyState();\n const previousVisible = lifecycle.visible;\n const visible: BrowserRenderOwner =\n render._tag === 'Navigation'\n ? { _tag: 'Navigation', navigation: render.navigation }\n : render._tag === 'Discard'\n ? render.visible\n : { _tag: 'Stable' };\n lifecycle.visible = visible;\n\n if (\n previousVisible._tag === 'Navigation' &&\n (visible._tag !== 'Navigation' || visible.navigation !== previousVisible.navigation)\n ) {\n retireNavigation(lifecycle, previousVisible.navigation);\n }\n\n switch (render._tag) {\n case 'Initial':\n break;\n case 'Discard':\n retireNavigation(lifecycle, render.navigation);\n break;\n case 'Navigation':\n if (getNavigationPhase(lifecycle, render.navigation) === 'Scheduled') {\n lifecycle.phases.set(render.navigation, 'Visible');\n }\n if (\n lifecycle.active._tag === 'Navigation' &&\n lifecycle.active.navigation === render.navigation\n ) {\n lifecycle.active = { _tag: 'Stable' };\n lifecycle.stableRouteTree = render.routeTree;\n lifecycle.phases.set(render.navigation, 'Completed');\n }\n render.navigation.committed.resolve();\n break;\n case 'Refresh':\n lifecycle.stableRouteTree = render.routeTree;\n render.committed.resolve();\n break;\n }\n };\n\n return { commit, initialize, navigate, refresh };\n }),\n },\n) {\n static readonly layer = Layer.effect(this, this.make);\n\n static readonly layerTest = Layer.mock(this);\n}\n"],"names":["Context","Effect","Layer","MutableRef","getNavigationPhase","lifecycle","navigation","phase","undefined","TypeError","retireNavigation","BrowserRenderer","state","getReadyState","current","initialize","initialRouteTree","publish","WeakMap","navigate","routeTree","Promise","visible","refresh","committed","commit","render","previousVisible"],"mappings":"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"}
1
+ {"version":3,"file":"client/browser-renderer.js","sources":["../../src/client/browser-renderer.ts"],"sourcesContent":["import { Context, Effect, Layer, MutableRef } from 'effect';\n\nimport type { RouteTreeModel } from '../rsc/route-tree';\n\nexport type BrowserRendererNavigation = {\n readonly committed: Promise<void>;\n readonly discard: () => Promise<void>;\n readonly retired: Promise<void>;\n};\n\ntype InitialRender = {\n readonly _tag: 'Initial';\n readonly routeTree: RouteTreeModel;\n};\n\ntype RouteRender = {\n readonly _tag: 'Navigation' | 'Refresh';\n readonly order: number;\n readonly committed: PromiseWithResolvers<void>;\n readonly retired: PromiseWithResolvers<void>;\n readonly routeTree: RouteTreeModel;\n};\n\nexport type BrowserRender =\n | InitialRender\n | RouteRender\n | {\n readonly _tag: 'Discard';\n readonly order: number;\n readonly restore: InitialRender | RouteRender;\n };\n\ntype LiveRender = {\n readonly _tag: 'Scheduled' | 'DiscardRequested' | 'Committed';\n readonly lastPublicationOrder: number;\n};\n\ntype BrowserRendererState =\n | { readonly _tag: 'Uninitialized' }\n | {\n readonly _tag: 'Ready';\n current: BrowserRender;\n publicationOrder: number;\n readonly liveRenders: Map<RouteRender, LiveRender>;\n readonly publish: (render: BrowserRender) => void;\n };\n\nexport class BrowserRenderer extends Context.Service<BrowserRenderer>()(\n 'ersc/client/BrowserRenderer',\n {\n make: Effect.sync(() => {\n const state = MutableRef.make<BrowserRendererState>({ _tag: 'Uninitialized' });\n const publications = new WeakSet<BrowserRender>();\n const getReadyState = () => {\n const current = MutableRef.get(state);\n if (current._tag === 'Uninitialized') {\n throw new TypeError('BrowserRenderer must be initialized by ReactDOMRenderer.');\n }\n return current;\n };\n\n const initialize = (\n initialRouteTree: RouteTreeModel,\n publish: (render: BrowserRender) => void,\n ) => {\n const current = MutableRef.get(state);\n if (current._tag === 'Ready') {\n if (current.publish === publish) {\n return;\n }\n throw new TypeError('BrowserRenderer cannot be initialized by more than one React root.');\n }\n\n MutableRef.set(state, {\n _tag: 'Ready',\n current: { _tag: 'Initial', routeTree: initialRouteTree },\n publicationOrder: 0,\n liveRenders: new Map(),\n publish,\n });\n };\n\n const publish = (render: BrowserRender) => {\n publications.add(render);\n getReadyState().publish(render);\n };\n\n const schedule = (routeTree: RouteTreeModel, kind: 'Navigation' | 'Refresh') => {\n const ready = getReadyState();\n const order = ++ready.publicationOrder;\n const render: RouteRender = {\n _tag: kind,\n order,\n committed: Promise.withResolvers<void>(),\n retired: Promise.withResolvers<void>(),\n routeTree,\n };\n ready.liveRenders.set(render, { _tag: 'Scheduled', lastPublicationOrder: order });\n publish(render);\n\n return {\n committed: render.committed.promise,\n discard: () => {\n const live = ready.liveRenders.get(render);\n // Cancellation can arrive before the caller observes a commit or retirement.\n if (live?._tag !== 'Scheduled') {\n return render.retired.promise;\n }\n ready.liveRenders.set(render, {\n _tag: 'DiscardRequested',\n lastPublicationOrder: order,\n });\n const current = ready.current;\n const restore = current._tag === 'Discard' ? current.restore : current;\n const discardOrder = ++ready.publicationOrder;\n if (restore._tag !== 'Initial') {\n // Keep the tree alive even if another render commits before this discard.\n // Reinsertion keeps the map ordered by each render's last publication.\n ready.liveRenders.delete(restore);\n ready.liveRenders.set(restore, {\n _tag: 'Committed',\n lastPublicationOrder: discardOrder,\n });\n }\n publish({ _tag: 'Discard', order: discardOrder, restore });\n return render.retired.promise;\n },\n retired: render.retired.promise,\n };\n };\n\n const navigate = (routeTree: RouteTreeModel) => schedule(routeTree, 'Navigation');\n const refresh = (routeTree: RouteTreeModel) => schedule(routeTree, 'Refresh');\n\n const commit = (render: BrowserRender) => {\n const ready = getReadyState();\n if (render._tag === 'Initial') {\n return;\n }\n if (!publications.has(render)) {\n throw new TypeError('Browser render does not belong to this root.');\n }\n const current = ready.current;\n if (current._tag !== 'Initial' && render.order < current.order) {\n throw new TypeError('Browser renders must commit in publication order.');\n }\n const visible = render._tag === 'Discard' ? render.restore : render;\n if (visible._tag !== 'Initial') {\n const live = ready.liveRenders.get(visible);\n if (live === undefined) {\n throw new TypeError('A retired browser tree cannot commit.');\n }\n ready.liveRenders.set(visible, {\n _tag: 'Committed',\n lastPublicationOrder: live.lastPublicationOrder,\n });\n }\n ready.current = render;\n if (render._tag !== 'Discard') {\n render.committed.resolve();\n }\n\n // A later replacement commit supersedes earlier publications. A tree stays alive\n // while visible or referenced by a newer publication, including a pending discard.\n for (const [retained, live] of ready.liveRenders) {\n if (live.lastPublicationOrder > render.order) {\n break;\n }\n if (retained !== visible) {\n ready.liveRenders.delete(retained);\n retained.retired.resolve();\n }\n }\n };\n\n return { commit, initialize, navigate, refresh };\n }),\n },\n) {\n static readonly layer = Layer.effect(this, this.make);\n\n static readonly layerTest = Layer.mock(this);\n}\n"],"names":["Context","Effect","Layer","MutableRef","BrowserRenderer","state","publications","WeakSet","getReadyState","current","TypeError","initialize","initialRouteTree","publish","Map","render","schedule","routeTree","kind","ready","order","Promise","live","restore","discardOrder","navigate","refresh","commit","visible","undefined","retained"],"mappings":"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"}
@@ -125,22 +125,24 @@ const installCallServer = Effect.gen(function*() {
125
125
  return;
126
126
  }
127
127
  const commitRefresh = routeLoader.prepareRefresh(resource.payload.routeTree);
128
- let renderCommitted;
128
+ let published;
129
129
  yield* Effect.sync(()=>{
130
130
  startTransition(()=>{
131
131
  addTransitionType('server-function');
132
132
  // Do not return the commit Promise from React's Transition Action. React cannot commit the
133
133
  // render until that Action ends.
134
- renderCommitted = browserRenderer.refresh(resource.payload.routeTree);
134
+ published = browserRenderer.refresh(resource.payload.routeTree);
135
135
  });
136
136
  });
137
- yield* Effect.all([
137
+ yield* Effect.raceFirst(Effect.all([
138
138
  resource.completed,
139
- Effect.promise(()=>renderCommitted)
139
+ Effect.promise(()=>published.committed)
140
140
  ], {
141
141
  concurrency: 'unbounded',
142
142
  discard: true
143
- }).pipe(Effect.andThen(Effect.sync(commitRefresh)), Effect.onError(()=>resource.release), Effect.forkScoped);
143
+ }).pipe(Effect.andThen(Effect.sync(commitRefresh))), Effect.promise(()=>published.retired)).pipe(Effect.ensuring(resource.release), Effect.forkScoped({
144
+ startImmediately: true
145
+ }));
144
146
  });
145
147
  yield* Effect.sync(()=>{
146
148
  setServerCallback((id, args)=>{
@@ -1 +1 @@
1
- {"version":3,"file":"client/call-server.js","sources":["../../src/client/call-server.ts"],"sourcesContent":["import { Effect, MutableRef, Schema } from 'effect';\nimport { addTransitionType, startTransition } from 'react';\nimport {\n createTemporaryReferenceSet,\n encodeReply,\n setServerCallback,\n} from 'react-server-dom-rspack/client.browser';\n\nimport { BrowserEffectRunner } from './browser-effect-runner';\nimport { BrowserRenderer } from './browser-renderer';\nimport { FlightClient } from './flight-client';\nimport { NavigationApi } from './navigation-api';\nimport { RouteLoader } from './route-loader';\nimport { RouteRefresher } from './route-refresh';\n\nclass ServerFnCallError extends Schema.TaggedError<ServerFnCallError>()('ServerFnCallError', {\n cause: Schema.Defect(),\n message: Schema.String,\n}) {}\n\ntype ServerFnInvocation =\n | {\n readonly _tag: 'HistoryEntry';\n readonly id: string;\n readonly order: number;\n readonly url: string;\n }\n | { readonly _tag: 'CurrentUrl'; readonly order: number; readonly url: string };\n\ntype ServerFnRefreshSource = 'Response' | 'CurrentRoute';\n\nexport const installCallServer = Effect.gen(function* () {\n const browserRenderer = yield* BrowserRenderer;\n const navigationApi = yield* NavigationApi;\n const run = yield* BrowserEffectRunner;\n const flightClient = yield* FlightClient;\n const routeLoader = yield* RouteLoader;\n const routeRefresher = yield* RouteRefresher;\n const latestInvocationOrder = MutableRef.make(0);\n const selectRefreshSource = (invocation: ServerFnInvocation): ServerFnRefreshSource => {\n if (\n MutableRef.get(latestInvocationOrder) !== invocation.order ||\n navigationApi.getTransition() !== null\n ) {\n return 'CurrentRoute';\n }\n\n const currentEntry = navigationApi.getCurrentEntry();\n switch (invocation._tag) {\n case 'HistoryEntry':\n return currentEntry?.id === invocation.id ? 'Response' : 'CurrentRoute';\n case 'CurrentUrl':\n return currentEntry === null && navigationApi.getCurrentUrl() === invocation.url\n ? 'Response'\n : 'CurrentRoute';\n }\n };\n const callServer = Effect.fnUntraced(function* (\n id: string,\n args: ReadonlyArray<unknown>,\n invocationResult: PromiseWithResolvers<unknown>,\n ) {\n const currentEntry = navigationApi.getCurrentEntry();\n const order = MutableRef.incrementAndGet(latestInvocationOrder);\n const invocation: ServerFnInvocation =\n currentEntry === null\n ? { _tag: 'CurrentUrl', order, url: navigationApi.getCurrentUrl() }\n : {\n _tag: 'HistoryEntry',\n id: currentEntry.id,\n order,\n url: currentEntry.url ?? navigationApi.getCurrentUrl(),\n };\n const temporaryReferences = createTemporaryReferenceSet();\n const body = yield* Effect.tryPromise({\n try: () => encodeReply(args, { temporaryReferences }),\n catch: (cause) => new ServerFnCallError({ cause, message: 'Failed to encode arguments.' }),\n });\n const resource = yield* flightClient\n .load({\n _tag: 'ServerFunction',\n body,\n destination: new URL(invocation.url),\n id,\n temporaryReferences,\n })\n .pipe(\n Effect.mapError(\n (cause) => new ServerFnCallError({ cause, message: 'Server Function request failed.' }),\n ),\n );\n if (resource._tag === 'Document') {\n yield* resource.release;\n return yield* new ServerFnCallError({\n cause: new Error('A Server Function response cannot request document navigation.'),\n message: 'Server Function response was incompatible with Flight.',\n });\n }\n const serverFnResult = resource.payload.serverFnResult;\n if (serverFnResult === null) {\n yield* resource.release;\n return yield* new ServerFnCallError({\n cause: new Error('The Flight payload omitted the Server Function return value.'),\n message: 'Server Function response was incomplete.',\n });\n }\n switch (serverFnResult._tag) {\n case 'Failure':\n invocationResult.reject(\n new ServerFnCallError({\n cause: serverFnResult.error,\n message: 'Server Function execution failed.',\n }),\n );\n break;\n case 'Success':\n invocationResult.resolve(serverFnResult.value);\n break;\n }\n // React registered its Action reactions before the request completed. Registering ERSC's\n // continuation after settlement lets React close that Action before the refresh Transition.\n yield* Effect.promise(() =>\n invocationResult.promise.then(\n () => undefined,\n () => undefined,\n ),\n );\n let refreshSource = selectRefreshSource(invocation);\n if (refreshSource === 'Response') {\n yield* routeRefresher.interruptCurrentRouteRefresh;\n // Interruption awaits cleanup, during which navigation or another invocation can win.\n refreshSource = selectRefreshSource(invocation);\n }\n\n if (refreshSource === 'CurrentRoute') {\n yield* resource.release;\n yield* routeRefresher.refreshCurrentRoute('server-function');\n return;\n }\n const commitRefresh = routeLoader.prepareRefresh(resource.payload.routeTree);\n let renderCommitted!: Promise<void>;\n yield* Effect.sync(() => {\n startTransition(() => {\n addTransitionType('server-function');\n // Do not return the commit Promise from React's Transition Action. React cannot commit the\n // render until that Action ends.\n renderCommitted = browserRenderer.refresh(resource.payload.routeTree);\n });\n });\n yield* Effect.all([resource.completed, Effect.promise(() => renderCommitted)], {\n concurrency: 'unbounded',\n discard: true,\n }).pipe(\n Effect.andThen(Effect.sync(commitRefresh)),\n Effect.onError(() => resource.release),\n Effect.forkScoped,\n );\n });\n\n yield* Effect.sync(() => {\n setServerCallback((id, args) => {\n const invocationResult = Promise.withResolvers<unknown>();\n void run(callServer(id, args, invocationResult)).catch(invocationResult.reject);\n return invocationResult.promise;\n });\n });\n});\n"],"names":["Effect","MutableRef","Schema","addTransitionType","startTransition","createTemporaryReferenceSet","encodeReply","setServerCallback","BrowserEffectRunner","BrowserRenderer","FlightClient","NavigationApi","RouteLoader","RouteRefresher","ServerFnCallError","installCallServer","browserRenderer","navigationApi","run","flightClient","routeLoader","routeRefresher","latestInvocationOrder","selectRefreshSource","invocation","currentEntry","callServer","id","args","invocationResult","order","temporaryReferences","body","cause","resource","URL","Error","serverFnResult","undefined","refreshSource","commitRefresh","renderCommitted","Promise"],"mappings":"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"}
1
+ {"version":3,"file":"client/call-server.js","sources":["../../src/client/call-server.ts"],"sourcesContent":["import { Effect, MutableRef, Schema } from 'effect';\nimport { addTransitionType, startTransition } from 'react';\nimport {\n createTemporaryReferenceSet,\n encodeReply,\n setServerCallback,\n} from 'react-server-dom-rspack/client.browser';\n\nimport { BrowserEffectRunner } from './browser-effect-runner';\nimport { BrowserRenderer } from './browser-renderer';\nimport { FlightClient } from './flight-client';\nimport { NavigationApi } from './navigation-api';\nimport { RouteLoader } from './route-loader';\nimport { RouteRefresher } from './route-refresh';\n\nclass ServerFnCallError extends Schema.TaggedError<ServerFnCallError>()('ServerFnCallError', {\n cause: Schema.Defect(),\n message: Schema.String,\n}) {}\n\ntype ServerFnInvocation =\n | {\n readonly _tag: 'HistoryEntry';\n readonly id: string;\n readonly order: number;\n readonly url: string;\n }\n | { readonly _tag: 'CurrentUrl'; readonly order: number; readonly url: string };\n\ntype ServerFnRefreshSource = 'Response' | 'CurrentRoute';\n\nexport const installCallServer = Effect.gen(function* () {\n const browserRenderer = yield* BrowserRenderer;\n const navigationApi = yield* NavigationApi;\n const run = yield* BrowserEffectRunner;\n const flightClient = yield* FlightClient;\n const routeLoader = yield* RouteLoader;\n const routeRefresher = yield* RouteRefresher;\n const latestInvocationOrder = MutableRef.make(0);\n const selectRefreshSource = (invocation: ServerFnInvocation): ServerFnRefreshSource => {\n if (\n MutableRef.get(latestInvocationOrder) !== invocation.order ||\n navigationApi.getTransition() !== null\n ) {\n return 'CurrentRoute';\n }\n\n const currentEntry = navigationApi.getCurrentEntry();\n switch (invocation._tag) {\n case 'HistoryEntry':\n return currentEntry?.id === invocation.id ? 'Response' : 'CurrentRoute';\n case 'CurrentUrl':\n return currentEntry === null && navigationApi.getCurrentUrl() === invocation.url\n ? 'Response'\n : 'CurrentRoute';\n }\n };\n const callServer = Effect.fnUntraced(function* (\n id: string,\n args: ReadonlyArray<unknown>,\n invocationResult: PromiseWithResolvers<unknown>,\n ) {\n const currentEntry = navigationApi.getCurrentEntry();\n const order = MutableRef.incrementAndGet(latestInvocationOrder);\n const invocation: ServerFnInvocation =\n currentEntry === null\n ? { _tag: 'CurrentUrl', order, url: navigationApi.getCurrentUrl() }\n : {\n _tag: 'HistoryEntry',\n id: currentEntry.id,\n order,\n url: currentEntry.url ?? navigationApi.getCurrentUrl(),\n };\n const temporaryReferences = createTemporaryReferenceSet();\n const body = yield* Effect.tryPromise({\n try: () => encodeReply(args, { temporaryReferences }),\n catch: (cause) => new ServerFnCallError({ cause, message: 'Failed to encode arguments.' }),\n });\n const resource = yield* flightClient\n .load({\n _tag: 'ServerFunction',\n body,\n destination: new URL(invocation.url),\n id,\n temporaryReferences,\n })\n .pipe(\n Effect.mapError(\n (cause) => new ServerFnCallError({ cause, message: 'Server Function request failed.' }),\n ),\n );\n if (resource._tag === 'Document') {\n yield* resource.release;\n return yield* new ServerFnCallError({\n cause: new Error('A Server Function response cannot request document navigation.'),\n message: 'Server Function response was incompatible with Flight.',\n });\n }\n const serverFnResult = resource.payload.serverFnResult;\n if (serverFnResult === null) {\n yield* resource.release;\n return yield* new ServerFnCallError({\n cause: new Error('The Flight payload omitted the Server Function return value.'),\n message: 'Server Function response was incomplete.',\n });\n }\n switch (serverFnResult._tag) {\n case 'Failure':\n invocationResult.reject(\n new ServerFnCallError({\n cause: serverFnResult.error,\n message: 'Server Function execution failed.',\n }),\n );\n break;\n case 'Success':\n invocationResult.resolve(serverFnResult.value);\n break;\n }\n // React registered its Action reactions before the request completed. Registering ERSC's\n // continuation after settlement lets React close that Action before the refresh Transition.\n yield* Effect.promise(() =>\n invocationResult.promise.then(\n () => undefined,\n () => undefined,\n ),\n );\n let refreshSource = selectRefreshSource(invocation);\n if (refreshSource === 'Response') {\n yield* routeRefresher.interruptCurrentRouteRefresh;\n // Interruption awaits cleanup, during which navigation or another invocation can win.\n refreshSource = selectRefreshSource(invocation);\n }\n\n if (refreshSource === 'CurrentRoute') {\n yield* resource.release;\n yield* routeRefresher.refreshCurrentRoute('server-function');\n return;\n }\n const commitRefresh = routeLoader.prepareRefresh(resource.payload.routeTree);\n let published!: ReturnType<BrowserRenderer['Service']['refresh']>;\n yield* Effect.sync(() => {\n startTransition(() => {\n addTransitionType('server-function');\n // Do not return the commit Promise from React's Transition Action. React cannot commit the\n // render until that Action ends.\n published = browserRenderer.refresh(resource.payload.routeTree);\n });\n });\n yield* Effect.raceFirst(\n Effect.all([resource.completed, Effect.promise(() => published.committed)], {\n concurrency: 'unbounded',\n discard: true,\n }).pipe(Effect.andThen(Effect.sync(commitRefresh))),\n Effect.promise(() => published.retired),\n ).pipe(Effect.ensuring(resource.release), Effect.forkScoped({ startImmediately: true }));\n });\n\n yield* Effect.sync(() => {\n setServerCallback((id, args) => {\n const invocationResult = Promise.withResolvers<unknown>();\n void run(callServer(id, args, invocationResult)).catch(invocationResult.reject);\n return invocationResult.promise;\n });\n });\n});\n"],"names":["Effect","MutableRef","Schema","addTransitionType","startTransition","createTemporaryReferenceSet","encodeReply","setServerCallback","BrowserEffectRunner","BrowserRenderer","FlightClient","NavigationApi","RouteLoader","RouteRefresher","ServerFnCallError","installCallServer","browserRenderer","navigationApi","run","flightClient","routeLoader","routeRefresher","latestInvocationOrder","selectRefreshSource","invocation","currentEntry","callServer","id","args","invocationResult","order","temporaryReferences","body","cause","resource","URL","Error","serverFnResult","undefined","refreshSource","commitRefresh","published","Promise"],"mappings":"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"}
@@ -20,6 +20,21 @@ import { RouteLoader } from "./route-loader.js";
20
20
 
21
21
 
22
22
 
23
+ const reservedTransitionTypes = new Set([
24
+ 'navigation',
25
+ 'server-function',
26
+ 'hmr-refresh'
27
+ ]);
28
+ const isApplicationTransitionType = (type)=>!reservedTransitionTypes.has(type) && !type.startsWith('navigation-');
29
+ const getLinkTransitionTypes = (event)=>{
30
+ if (event.navigationType !== 'push' && event.navigationType !== 'replace' || !(event.sourceElement instanceof HTMLAnchorElement)) {
31
+ return [];
32
+ }
33
+ const types = event.sourceElement.dataset['erscTransitionTypes']?.match(/\S+/g) ?? [];
34
+ return [
35
+ ...new Set(types.filter(isApplicationTransitionType))
36
+ ];
37
+ };
23
38
  const getNavigationTransitionTypes = (event, fromIndex)=>{
24
39
  const types = [
25
40
  'navigation',
@@ -51,10 +66,7 @@ const reduceRouterState = (state, event)=>{
51
66
  switch(event._tag){
52
67
  case 'RenderRetired':
53
68
  return {
54
- command: visible.flight._tag === 'Streaming' ? {
55
- _tag: 'ReleaseRoute',
56
- resource: visible.flight.resource
57
- } : null,
69
+ command: null,
58
70
  state: {
59
71
  ...state,
60
72
  visible: {
@@ -384,6 +396,7 @@ const installClientRouter = Effect.gen(function*() {
384
396
  return;
385
397
  }
386
398
  const destination = new URL(event.destination.url);
399
+ const linkTransitionTypes = getLinkTransitionTypes(event);
387
400
  const generation = Symbol('NavigationGeneration');
388
401
  const lifetime = new AbortController();
389
402
  const navigationSignal = AbortSignal.any([
@@ -463,6 +476,9 @@ const installClientRouter = Effect.gen(function*() {
463
476
  for (const type of getNavigationTransitionTypes(event, fromIndex)){
464
477
  addTransitionType(type);
465
478
  }
479
+ for (const type of linkTransitionTypes){
480
+ addTransitionType(type);
481
+ }
466
482
  navigation = browserRenderer.navigate(command.resource.routeTree);
467
483
  });
468
484
  return navigation;
@@ -538,12 +554,12 @@ const installClientRouter = Effect.gen(function*() {
538
554
  }
539
555
  const waitForRenderRetirement = Effect.gen(function*() {
540
556
  yield* Effect.promise(()=>rendererNavigation.retired);
541
- const transition = dispatch({
557
+ dispatch({
542
558
  _tag: 'RenderRetired',
543
559
  generation
544
560
  });
545
- yield* executeRouterCommand(transition.command);
546
- }).pipe(Effect.ignore);
561
+ }).pipe(// A newer generation may already be current when this render retires.
562
+ Effect.ensuring(resource.release), Effect.ignore);
547
563
  void run(waitForRenderRetirement).catch(()=>undefined);
548
564
  const waitForFlightCompletion = Effect.gen(function*() {
549
565
  const flightExit = yield* Effect.exit(resource.completed);
@@ -1 +1 @@
1
- {"version":3,"file":"client/client-router.js","sources":["../../src/client/client-router.ts"],"sourcesContent":["import { Effect, Exit, MutableRef } from 'effect';\nimport { addTransitionType, startTransition } from 'react';\n\nimport { BrowserEffectRunner } from './browser-effect-runner';\nimport { BrowserRenderer, type BrowserRendererNavigation } from './browser-renderer';\nimport { NavigationApi } from './navigation-api';\nimport {\n isRoutedNavigation,\n NativeDocumentNavigationInfo,\n preserveRequestedHash,\n} from './navigation-routing';\nimport { RouteLoader, type RouteLoad } from './route-loader';\n\ntype NavigationGeneration = symbol;\ntype RouteResource = Extract<RouteLoad, { readonly _tag: 'Route' }>;\n\nconst getNavigationTransitionTypes = (\n event: NavigateEvent,\n fromIndex: number | null,\n): ReadonlyArray<string> => {\n const types = [\n 'navigation',\n `navigation-${event.navigationType}`,\n ...(event.hasUAVisualTransition ? ['navigation-ua-visual-transition'] : []),\n ];\n if (event.navigationType === 'push') {\n return [...types, 'navigation-forward'];\n }\n if (event.navigationType !== 'traverse') {\n return types;\n }\n\n if (fromIndex === null || fromIndex === event.destination.index) {\n return types;\n }\n return [\n ...types,\n event.destination.index < fromIndex ? 'navigation-backward' : 'navigation-forward',\n ];\n};\n\ntype NavigationEntryState =\n | { readonly _tag: 'PendingCommit' }\n | {\n readonly _tag: 'Committed';\n readonly entry: NavigationHistoryEntry | null;\n };\n\ntype NavigationFlightState =\n | { readonly _tag: 'Streaming'; readonly resource: RouteResource }\n | { readonly _tag: 'Completed'; readonly cache: RouteResource['cache'] };\n\ntype NavigationCandidate =\n | {\n readonly _tag: 'Loading';\n readonly generation: NavigationGeneration;\n readonly lifetime: AbortController;\n }\n | {\n readonly _tag: 'Publishing';\n readonly generation: NavigationGeneration;\n readonly lifetime: AbortController;\n readonly resource: RouteResource;\n }\n | {\n readonly _tag: 'Rendering';\n readonly generation: NavigationGeneration;\n readonly lifetime: AbortController;\n readonly rendererNavigation: BrowserRendererNavigation;\n readonly resource: RouteResource;\n };\n\ntype VisibleNavigation =\n | { readonly _tag: 'Settled' }\n | {\n readonly _tag: 'Navigation';\n readonly entry: NavigationEntryState;\n readonly flight: NavigationFlightState;\n readonly generation: NavigationGeneration;\n };\n\ntype RouterState =\n | { readonly _tag: 'Ready'; readonly visible: VisibleNavigation }\n | {\n readonly _tag: 'Navigating';\n readonly candidate: NavigationCandidate;\n readonly visible: VisibleNavigation;\n };\n\ntype RouterEvent =\n | {\n readonly _tag: 'BeginNavigation';\n readonly generation: NavigationGeneration;\n readonly lifetime: AbortController;\n }\n | { readonly _tag: 'DocumentLoaded'; readonly generation: NavigationGeneration }\n | {\n readonly _tag: 'RouteLoaded';\n readonly generation: NavigationGeneration;\n readonly resource: RouteResource;\n }\n | {\n readonly _tag: 'RenderScheduled';\n readonly generation: NavigationGeneration;\n readonly rendererNavigation: BrowserRendererNavigation;\n readonly resource: RouteResource;\n }\n | { readonly _tag: 'RenderCommitted'; readonly generation: NavigationGeneration }\n | { readonly _tag: 'RenderRetired'; readonly generation: NavigationGeneration }\n | {\n readonly _tag: 'HistoryCommitted';\n readonly entry: NavigationHistoryEntry | null;\n readonly generation: NavigationGeneration;\n }\n | { readonly _tag: 'FlightCompleted'; readonly generation: NavigationGeneration }\n | { readonly _tag: 'FlightFailed'; readonly generation: NavigationGeneration }\n | { readonly _tag: 'NavigationAborted'; readonly generation: NavigationGeneration };\n\ntype RouterCommand =\n | { readonly _tag: 'SupersedeCandidate'; readonly candidate: NavigationCandidate }\n | {\n readonly _tag: 'PublishRoute';\n readonly generation: NavigationGeneration;\n readonly resource: RouteResource;\n }\n | { readonly _tag: 'ReleaseRoute'; readonly resource: RouteResource }\n | {\n readonly _tag: 'CacheRoute';\n readonly cache: RouteResource['cache'];\n readonly entry: NavigationHistoryEntry;\n }\n | {\n readonly _tag: 'CacheAndReleaseRoute';\n readonly entry: NavigationHistoryEntry;\n readonly resource: RouteResource;\n }\n | {\n readonly _tag: 'DiscardRoute';\n readonly rendererNavigation: BrowserRendererNavigation;\n readonly resource: RouteResource;\n };\n\ntype RouterTransition = {\n readonly command: RouterCommand | null;\n readonly state: RouterState;\n};\n\nconst reduceRouterState = (state: RouterState, event: RouterEvent): RouterTransition => {\n if (state.visible._tag === 'Navigation' && state.visible.generation === event.generation) {\n const visible = state.visible;\n switch (event._tag) {\n case 'RenderRetired':\n return {\n command:\n visible.flight._tag === 'Streaming'\n ? { _tag: 'ReleaseRoute', resource: visible.flight.resource }\n : null,\n state: { ...state, visible: { _tag: 'Settled' } },\n };\n case 'HistoryCommitted':\n if (visible.entry._tag === 'Committed') {\n throw new TypeError('A visible navigation history entry cannot commit twice.');\n }\n if (visible.flight._tag === 'Streaming') {\n return {\n command: null,\n state: {\n ...state,\n visible: {\n ...visible,\n entry: { _tag: 'Committed', entry: event.entry },\n },\n },\n };\n }\n return {\n command:\n event.entry === null\n ? null\n : { _tag: 'CacheRoute', cache: visible.flight.cache, entry: event.entry },\n state: { ...state, visible: { _tag: 'Settled' } },\n };\n case 'FlightCompleted':\n if (visible.flight._tag === 'Completed') {\n throw new TypeError('A visible navigation Flight stream cannot complete twice.');\n }\n if (visible.entry._tag === 'PendingCommit') {\n return {\n command: { _tag: 'ReleaseRoute', resource: visible.flight.resource },\n state: {\n ...state,\n visible: {\n ...visible,\n flight: { _tag: 'Completed', cache: visible.flight.resource.cache },\n },\n },\n };\n }\n return {\n command:\n visible.entry.entry === null\n ? { _tag: 'ReleaseRoute', resource: visible.flight.resource }\n : {\n _tag: 'CacheAndReleaseRoute',\n entry: visible.entry.entry,\n resource: visible.flight.resource,\n },\n state: { ...state, visible: { _tag: 'Settled' } },\n };\n case 'FlightFailed':\n if (visible.flight._tag === 'Completed') {\n throw new TypeError('A completed visible Flight stream cannot fail.');\n }\n return {\n command: { _tag: 'ReleaseRoute', resource: visible.flight.resource },\n state: { ...state, visible: { _tag: 'Settled' } },\n };\n }\n }\n\n if (\n event._tag === 'RenderRetired' ||\n event._tag === 'HistoryCommitted' ||\n event._tag === 'FlightCompleted'\n ) {\n return { command: null, state };\n }\n\n if (event._tag === 'BeginNavigation') {\n const nextState: RouterState = {\n _tag: 'Navigating',\n candidate: {\n _tag: 'Loading',\n generation: event.generation,\n lifetime: event.lifetime,\n },\n visible: state.visible,\n };\n if (state._tag === 'Ready') {\n return { command: null, state: nextState };\n }\n return {\n command: { _tag: 'SupersedeCandidate', candidate: state.candidate },\n state: nextState,\n };\n }\n\n if (state._tag === 'Ready' || state.candidate.generation !== event.generation) {\n switch (event._tag) {\n case 'RouteLoaded':\n return { command: { _tag: 'ReleaseRoute', resource: event.resource }, state };\n case 'RenderScheduled':\n return {\n command: {\n _tag: 'DiscardRoute',\n rendererNavigation: event.rendererNavigation,\n resource: event.resource,\n },\n state,\n };\n default:\n return { command: null, state };\n }\n }\n\n switch (event._tag) {\n case 'DocumentLoaded':\n case 'FlightFailed':\n if (state.candidate._tag !== 'Loading') {\n throw new TypeError(`${event._tag} cannot follow ${state.candidate._tag}.`);\n }\n return { command: null, state: { _tag: 'Ready', visible: state.visible } };\n case 'RouteLoaded':\n if (state.candidate._tag !== 'Loading') {\n throw new TypeError(`RouteLoaded cannot follow ${state.candidate._tag}.`);\n }\n return {\n command: {\n _tag: 'PublishRoute',\n generation: event.generation,\n resource: event.resource,\n },\n state: {\n _tag: 'Navigating',\n candidate: {\n _tag: 'Publishing',\n generation: event.generation,\n lifetime: state.candidate.lifetime,\n resource: event.resource,\n },\n visible: state.visible,\n },\n };\n case 'RenderScheduled':\n if (state.candidate._tag !== 'Publishing') {\n throw new TypeError(`RenderScheduled cannot follow ${state.candidate._tag}.`);\n }\n if (state.candidate.resource !== event.resource) {\n throw new TypeError('RenderScheduled must use the published route resource.');\n }\n return {\n command: null,\n state: {\n _tag: 'Navigating',\n candidate: {\n _tag: 'Rendering',\n generation: event.generation,\n lifetime: state.candidate.lifetime,\n rendererNavigation: event.rendererNavigation,\n resource: event.resource,\n },\n visible: state.visible,\n },\n };\n case 'RenderCommitted':\n if (state.candidate._tag !== 'Rendering') {\n throw new TypeError(`RenderCommitted cannot follow ${state.candidate._tag}.`);\n }\n return {\n command: null,\n state: {\n _tag: 'Ready',\n visible: {\n _tag: 'Navigation',\n entry: { _tag: 'PendingCommit' },\n flight: { _tag: 'Streaming', resource: state.candidate.resource },\n generation: event.generation,\n },\n },\n };\n case 'NavigationAborted':\n if (state.candidate._tag === 'Loading') {\n return { command: null, state: { _tag: 'Ready', visible: state.visible } };\n }\n if (state.candidate._tag === 'Publishing') {\n return {\n command: { _tag: 'ReleaseRoute', resource: state.candidate.resource },\n state: { _tag: 'Ready', visible: state.visible },\n };\n }\n return {\n command: {\n _tag: 'DiscardRoute',\n rendererNavigation: state.candidate.rendererNavigation,\n resource: state.candidate.resource,\n },\n state: { _tag: 'Ready', visible: state.visible },\n };\n }\n};\n\ntype NavigationPreparation =\n | { readonly _tag: 'Handled' }\n | {\n readonly _tag: 'Rendered';\n readonly rendererNavigation: BrowserRendererNavigation;\n readonly resolvedDestination: URL;\n readonly resource: RouteResource;\n };\n\nexport const installClientRouter = Effect.gen(function* () {\n const browserRenderer = yield* BrowserRenderer;\n const navigationApi = yield* NavigationApi;\n const routeLoader = yield* RouteLoader;\n const run = yield* BrowserEffectRunner;\n const routerState = MutableRef.make<RouterState>({\n _tag: 'Ready',\n visible: { _tag: 'Settled' },\n });\n\n const dispatch = (event: RouterEvent) => {\n const transition = reduceRouterState(MutableRef.get(routerState), event);\n MutableRef.set(routerState, transition.state);\n return transition;\n };\n\n const executeRouterCommand = Effect.fnUntraced(function* (command: RouterCommand | null) {\n if (command === null) {\n return;\n }\n switch (command._tag) {\n case 'SupersedeCandidate': {\n const candidate = command.candidate;\n yield* Effect.sync(() => candidate.lifetime.abort());\n if (candidate._tag === 'Loading') {\n break;\n }\n if (candidate._tag === 'Publishing') {\n yield* candidate.resource.release;\n break;\n }\n yield* Effect.promise(() => candidate.rendererNavigation.discard()).pipe(\n Effect.ensuring(candidate.resource.release),\n );\n break;\n }\n case 'ReleaseRoute':\n yield* command.resource.release;\n break;\n case 'CacheRoute':\n yield* Effect.sync(() => command.cache(command.entry));\n break;\n case 'CacheAndReleaseRoute':\n yield* Effect.sync(() => command.resource.cache(command.entry));\n yield* command.resource.release;\n break;\n case 'DiscardRoute':\n yield* Effect.promise(() => command.rendererNavigation.discard()).pipe(\n Effect.ensuring(command.resource.release),\n );\n break;\n default:\n throw new TypeError(`Cannot execute the ${command._tag} lifecycle command here.`);\n }\n });\n\n const openDocument = (event: NavigateEvent, destination: URL) => {\n if (event.navigationType === 'traverse') {\n navigationApi.replaceDocument(destination.href);\n return;\n }\n navigationApi.navigate(destination.href, {\n history: event.navigationType === 'replace' ? 'replace' : 'push',\n info: NativeDocumentNavigationInfo,\n });\n };\n\n const onNavigate = (event: NavigateEvent) => {\n if (!isRoutedNavigation(event)) {\n return;\n }\n\n const destination = new URL(event.destination.url);\n const generation: NavigationGeneration = Symbol('NavigationGeneration');\n const lifetime = new AbortController();\n const navigationSignal = AbortSignal.any([event.signal, lifetime.signal]);\n const begin = dispatch({\n _tag: 'BeginNavigation',\n generation,\n lifetime,\n });\n void run(executeRouterCommand(begin.command)).catch(() => undefined);\n // oxlint-disable-next-line effecttsgo/async-function -- Navigation handlers are native Promise boundaries.\n const handler = async (precommitController?: NavigationPrecommitController) => {\n const preparation = Promise.withResolvers<NavigationPreparation>();\n\n const navigationAction = Effect.gen(function* () {\n const resource = yield* routeLoader\n .load({\n destination: event.destination,\n navigationType: event.navigationType,\n })\n .pipe(\n Effect.onError(() =>\n Effect.sync(() => {\n dispatch({ _tag: 'FlightFailed', generation });\n }),\n ),\n );\n\n if (resource._tag === 'Document') {\n dispatch({ _tag: 'DocumentLoaded', generation });\n yield* resource.release;\n openDocument(event, destination);\n return { _tag: 'Handled' } as const;\n }\n\n const resolvedDestination = preserveRequestedHash(destination, resource.resolvedUrl);\n if (resolvedDestination.origin !== destination.origin) {\n dispatch({ _tag: 'DocumentLoaded', generation });\n yield* resource.release;\n openDocument(event, resolvedDestination);\n return { _tag: 'Handled' } as const;\n }\n\n if (\n destination.href !== resolvedDestination.href &&\n (precommitController === undefined || event.navigationType === 'traverse')\n ) {\n dispatch({ _tag: 'DocumentLoaded', generation });\n yield* resource.release;\n navigationApi.replaceDocument(resolvedDestination.href);\n return { _tag: 'Handled' } as const;\n }\n\n const transition = dispatch({ _tag: 'RouteLoaded', generation, resource });\n const command = transition.command;\n if (command?._tag === 'ReleaseRoute') {\n yield* command.resource.release;\n return { _tag: 'Handled' } as const;\n }\n if (command?._tag === 'PublishRoute') {\n const rendererNavigation = yield* Effect.sync(() => {\n let navigation!: BrowserRendererNavigation;\n startTransition(() => {\n const fromIndex =\n navigationApi.getTransition()?.from.index ??\n navigationApi.getCurrentEntry()?.index ??\n null;\n for (const type of getNavigationTransitionTypes(event, fromIndex)) {\n addTransitionType(type);\n }\n navigation = browserRenderer.navigate(command.resource.routeTree);\n });\n return navigation;\n });\n const scheduled = dispatch({\n _tag: 'RenderScheduled',\n generation: command.generation,\n rendererNavigation,\n resource: command.resource,\n });\n if (scheduled.command !== null) {\n yield* executeRouterCommand(scheduled.command);\n return { _tag: 'Handled' } as const;\n }\n return {\n _tag: 'Rendered',\n rendererNavigation,\n resolvedDestination,\n resource: command.resource,\n } as const;\n }\n\n throw new TypeError('A loaded route must be published or released.');\n });\n\n // oxlint-disable-next-line effecttsgo/async-function -- React Transition Actions are a native Promise boundary.\n startTransition(async () => {\n await run(navigationAction, { signal: navigationSignal })\n .then(preparation.resolve)\n .catch(preparation.reject);\n });\n\n const abortNavigation = Effect.suspend(() => {\n const transition = dispatch({ _tag: 'NavigationAborted', generation });\n return executeRouterCommand(transition.command);\n });\n const outcome = await preparation.promise.catch((cause) => {\n if (navigationSignal.aborted) {\n return run(abortNavigation.pipe(Effect.as({ _tag: 'Handled' } as NavigationPreparation)));\n }\n if (!event.cancelable && event.navigationType === 'traverse') {\n navigationApi.reloadDocument();\n return { _tag: 'Handled' } as NavigationPreparation;\n }\n throw cause;\n });\n if (outcome._tag === 'Handled') {\n return;\n }\n\n const { rendererNavigation, resolvedDestination, resource } = outcome;\n const waitForNavigationCommit = Effect.uninterruptibleMask((restore) =>\n restore(Effect.promise(() => rendererNavigation.committed)).pipe(\n Effect.tap(\n Effect.suspend(() => {\n const transition = dispatch({\n _tag: 'RenderCommitted',\n generation,\n });\n return executeRouterCommand(transition.command);\n }),\n ),\n Effect.onExit((exit) => (Exit.isFailure(exit) ? abortNavigation : Effect.void)),\n ),\n );\n try {\n await run(waitForNavigationCommit, { signal: navigationSignal });\n } catch (cause) {\n if (navigationSignal.aborted) {\n return;\n }\n throw cause;\n }\n\n const waitForRenderRetirement = Effect.gen(function* () {\n yield* Effect.promise(() => rendererNavigation.retired);\n const transition = dispatch({ _tag: 'RenderRetired', generation });\n yield* executeRouterCommand(transition.command);\n }).pipe(Effect.ignore);\n void run(waitForRenderRetirement).catch(() => undefined);\n\n const waitForFlightCompletion = Effect.gen(function* () {\n const flightExit = yield* Effect.exit(resource.completed);\n const transition = dispatch({\n _tag: Exit.isSuccess(flightExit) ? 'FlightCompleted' : 'FlightFailed',\n generation,\n });\n yield* executeRouterCommand(transition.command);\n });\n void run(waitForFlightCompletion).catch(() => undefined);\n\n if (destination.href !== resolvedDestination.href && precommitController !== undefined) {\n precommitController.redirect(resolvedDestination.href, { history: 'auto' });\n }\n const commitHistory = Effect.suspend(() => {\n const transition = dispatch({\n _tag: 'HistoryCommitted',\n entry: navigationApi.getCurrentEntry(),\n generation,\n });\n return executeRouterCommand(transition.command);\n });\n if (precommitController === undefined) {\n await run(commitHistory);\n } else {\n precommitController.addHandler(() => run(commitHistory));\n }\n };\n\n event.intercept(\n event.cancelable\n ? { precommitHandler: handler }\n : {\n // Browsers make some traversals non-cancelable so an application cannot trap users.\n handler,\n },\n );\n };\n\n yield* Effect.acquireRelease(\n Effect.sync(() => navigationApi.subscribe(onNavigate)),\n (unsubscribe) => Effect.sync(unsubscribe),\n );\n});\n"],"names":["Effect","Exit","MutableRef","addTransitionType","startTransition","BrowserEffectRunner","BrowserRenderer","NavigationApi","isRoutedNavigation","NativeDocumentNavigationInfo","preserveRequestedHash","RouteLoader","getNavigationTransitionTypes","event","fromIndex","types","reduceRouterState","state","visible","TypeError","nextState","installClientRouter","browserRenderer","navigationApi","routeLoader","run","routerState","dispatch","transition","executeRouterCommand","command","candidate","openDocument","destination","onNavigate","URL","generation","Symbol","lifetime","AbortController","navigationSignal","AbortSignal","begin","undefined","handler","precommitController","preparation","Promise","navigationAction","resource","resolvedDestination","rendererNavigation","navigation","type","scheduled","abortNavigation","outcome","cause","waitForNavigationCommit","restore","exit","waitForRenderRetirement","waitForFlightCompletion","flightExit","commitHistory","unsubscribe"],"mappings":"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"}
1
+ {"version":3,"file":"client/client-router.js","sources":["../../src/client/client-router.ts"],"sourcesContent":["import { Effect, Exit, MutableRef } from 'effect';\nimport { addTransitionType, startTransition } from 'react';\n\nimport { BrowserEffectRunner } from './browser-effect-runner';\nimport { BrowserRenderer, type BrowserRendererNavigation } from './browser-renderer';\nimport { NavigationApi } from './navigation-api';\nimport {\n isRoutedNavigation,\n NativeDocumentNavigationInfo,\n preserveRequestedHash,\n} from './navigation-routing';\nimport { RouteLoader, type RouteLoad } from './route-loader';\n\ntype NavigationGeneration = symbol;\ntype RouteResource = Extract<RouteLoad, { readonly _tag: 'Route' }>;\n\nconst reservedTransitionTypes = new Set(['navigation', 'server-function', 'hmr-refresh']);\n\nconst isApplicationTransitionType = (type: string) =>\n !reservedTransitionTypes.has(type) && !type.startsWith('navigation-');\n\nconst getLinkTransitionTypes = (event: NavigateEvent): ReadonlyArray<string> => {\n if (\n (event.navigationType !== 'push' && event.navigationType !== 'replace') ||\n !(event.sourceElement instanceof HTMLAnchorElement)\n ) {\n return [];\n }\n const types = event.sourceElement.dataset['erscTransitionTypes']?.match(/\\S+/g) ?? [];\n return [...new Set(types.filter(isApplicationTransitionType))];\n};\n\nconst getNavigationTransitionTypes = (\n event: NavigateEvent,\n fromIndex: number | null,\n): ReadonlyArray<string> => {\n const types = [\n 'navigation',\n `navigation-${event.navigationType}`,\n ...(event.hasUAVisualTransition ? ['navigation-ua-visual-transition'] : []),\n ];\n if (event.navigationType === 'push') {\n return [...types, 'navigation-forward'];\n }\n if (event.navigationType !== 'traverse') {\n return types;\n }\n\n if (fromIndex === null || fromIndex === event.destination.index) {\n return types;\n }\n return [\n ...types,\n event.destination.index < fromIndex ? 'navigation-backward' : 'navigation-forward',\n ];\n};\n\ntype NavigationEntryState =\n | { readonly _tag: 'PendingCommit' }\n | {\n readonly _tag: 'Committed';\n readonly entry: NavigationHistoryEntry | null;\n };\n\ntype NavigationFlightState =\n | { readonly _tag: 'Streaming'; readonly resource: RouteResource }\n | { readonly _tag: 'Completed'; readonly cache: RouteResource['cache'] };\n\ntype NavigationCandidate =\n | {\n readonly _tag: 'Loading';\n readonly generation: NavigationGeneration;\n readonly lifetime: AbortController;\n }\n | {\n readonly _tag: 'Publishing';\n readonly generation: NavigationGeneration;\n readonly lifetime: AbortController;\n readonly resource: RouteResource;\n }\n | {\n readonly _tag: 'Rendering';\n readonly generation: NavigationGeneration;\n readonly lifetime: AbortController;\n readonly rendererNavigation: BrowserRendererNavigation;\n readonly resource: RouteResource;\n };\n\ntype VisibleNavigation =\n | { readonly _tag: 'Settled' }\n | {\n readonly _tag: 'Navigation';\n readonly entry: NavigationEntryState;\n readonly flight: NavigationFlightState;\n readonly generation: NavigationGeneration;\n };\n\ntype RouterState =\n | { readonly _tag: 'Ready'; readonly visible: VisibleNavigation }\n | {\n readonly _tag: 'Navigating';\n readonly candidate: NavigationCandidate;\n readonly visible: VisibleNavigation;\n };\n\ntype RouterEvent =\n | {\n readonly _tag: 'BeginNavigation';\n readonly generation: NavigationGeneration;\n readonly lifetime: AbortController;\n }\n | { readonly _tag: 'DocumentLoaded'; readonly generation: NavigationGeneration }\n | {\n readonly _tag: 'RouteLoaded';\n readonly generation: NavigationGeneration;\n readonly resource: RouteResource;\n }\n | {\n readonly _tag: 'RenderScheduled';\n readonly generation: NavigationGeneration;\n readonly rendererNavigation: BrowserRendererNavigation;\n readonly resource: RouteResource;\n }\n | { readonly _tag: 'RenderCommitted'; readonly generation: NavigationGeneration }\n | { readonly _tag: 'RenderRetired'; readonly generation: NavigationGeneration }\n | {\n readonly _tag: 'HistoryCommitted';\n readonly entry: NavigationHistoryEntry | null;\n readonly generation: NavigationGeneration;\n }\n | { readonly _tag: 'FlightCompleted'; readonly generation: NavigationGeneration }\n | { readonly _tag: 'FlightFailed'; readonly generation: NavigationGeneration }\n | { readonly _tag: 'NavigationAborted'; readonly generation: NavigationGeneration };\n\ntype RouterCommand =\n | { readonly _tag: 'SupersedeCandidate'; readonly candidate: NavigationCandidate }\n | {\n readonly _tag: 'PublishRoute';\n readonly generation: NavigationGeneration;\n readonly resource: RouteResource;\n }\n | { readonly _tag: 'ReleaseRoute'; readonly resource: RouteResource }\n | {\n readonly _tag: 'CacheRoute';\n readonly cache: RouteResource['cache'];\n readonly entry: NavigationHistoryEntry;\n }\n | {\n readonly _tag: 'CacheAndReleaseRoute';\n readonly entry: NavigationHistoryEntry;\n readonly resource: RouteResource;\n }\n | {\n readonly _tag: 'DiscardRoute';\n readonly rendererNavigation: BrowserRendererNavigation;\n readonly resource: RouteResource;\n };\n\ntype RouterTransition = {\n readonly command: RouterCommand | null;\n readonly state: RouterState;\n};\n\nconst reduceRouterState = (state: RouterState, event: RouterEvent): RouterTransition => {\n if (state.visible._tag === 'Navigation' && state.visible.generation === event.generation) {\n const visible = state.visible;\n switch (event._tag) {\n case 'RenderRetired':\n return {\n command: null,\n state: { ...state, visible: { _tag: 'Settled' } },\n };\n case 'HistoryCommitted':\n if (visible.entry._tag === 'Committed') {\n throw new TypeError('A visible navigation history entry cannot commit twice.');\n }\n if (visible.flight._tag === 'Streaming') {\n return {\n command: null,\n state: {\n ...state,\n visible: {\n ...visible,\n entry: { _tag: 'Committed', entry: event.entry },\n },\n },\n };\n }\n return {\n command:\n event.entry === null\n ? null\n : { _tag: 'CacheRoute', cache: visible.flight.cache, entry: event.entry },\n state: { ...state, visible: { _tag: 'Settled' } },\n };\n case 'FlightCompleted':\n if (visible.flight._tag === 'Completed') {\n throw new TypeError('A visible navigation Flight stream cannot complete twice.');\n }\n if (visible.entry._tag === 'PendingCommit') {\n return {\n command: { _tag: 'ReleaseRoute', resource: visible.flight.resource },\n state: {\n ...state,\n visible: {\n ...visible,\n flight: { _tag: 'Completed', cache: visible.flight.resource.cache },\n },\n },\n };\n }\n return {\n command:\n visible.entry.entry === null\n ? { _tag: 'ReleaseRoute', resource: visible.flight.resource }\n : {\n _tag: 'CacheAndReleaseRoute',\n entry: visible.entry.entry,\n resource: visible.flight.resource,\n },\n state: { ...state, visible: { _tag: 'Settled' } },\n };\n case 'FlightFailed':\n if (visible.flight._tag === 'Completed') {\n throw new TypeError('A completed visible Flight stream cannot fail.');\n }\n return {\n command: { _tag: 'ReleaseRoute', resource: visible.flight.resource },\n state: { ...state, visible: { _tag: 'Settled' } },\n };\n }\n }\n\n if (\n event._tag === 'RenderRetired' ||\n event._tag === 'HistoryCommitted' ||\n event._tag === 'FlightCompleted'\n ) {\n return { command: null, state };\n }\n\n if (event._tag === 'BeginNavigation') {\n const nextState: RouterState = {\n _tag: 'Navigating',\n candidate: {\n _tag: 'Loading',\n generation: event.generation,\n lifetime: event.lifetime,\n },\n visible: state.visible,\n };\n if (state._tag === 'Ready') {\n return { command: null, state: nextState };\n }\n return {\n command: { _tag: 'SupersedeCandidate', candidate: state.candidate },\n state: nextState,\n };\n }\n\n if (state._tag === 'Ready' || state.candidate.generation !== event.generation) {\n switch (event._tag) {\n case 'RouteLoaded':\n return { command: { _tag: 'ReleaseRoute', resource: event.resource }, state };\n case 'RenderScheduled':\n return {\n command: {\n _tag: 'DiscardRoute',\n rendererNavigation: event.rendererNavigation,\n resource: event.resource,\n },\n state,\n };\n default:\n return { command: null, state };\n }\n }\n\n switch (event._tag) {\n case 'DocumentLoaded':\n case 'FlightFailed':\n if (state.candidate._tag !== 'Loading') {\n throw new TypeError(`${event._tag} cannot follow ${state.candidate._tag}.`);\n }\n return { command: null, state: { _tag: 'Ready', visible: state.visible } };\n case 'RouteLoaded':\n if (state.candidate._tag !== 'Loading') {\n throw new TypeError(`RouteLoaded cannot follow ${state.candidate._tag}.`);\n }\n return {\n command: {\n _tag: 'PublishRoute',\n generation: event.generation,\n resource: event.resource,\n },\n state: {\n _tag: 'Navigating',\n candidate: {\n _tag: 'Publishing',\n generation: event.generation,\n lifetime: state.candidate.lifetime,\n resource: event.resource,\n },\n visible: state.visible,\n },\n };\n case 'RenderScheduled':\n if (state.candidate._tag !== 'Publishing') {\n throw new TypeError(`RenderScheduled cannot follow ${state.candidate._tag}.`);\n }\n if (state.candidate.resource !== event.resource) {\n throw new TypeError('RenderScheduled must use the published route resource.');\n }\n return {\n command: null,\n state: {\n _tag: 'Navigating',\n candidate: {\n _tag: 'Rendering',\n generation: event.generation,\n lifetime: state.candidate.lifetime,\n rendererNavigation: event.rendererNavigation,\n resource: event.resource,\n },\n visible: state.visible,\n },\n };\n case 'RenderCommitted':\n if (state.candidate._tag !== 'Rendering') {\n throw new TypeError(`RenderCommitted cannot follow ${state.candidate._tag}.`);\n }\n return {\n command: null,\n state: {\n _tag: 'Ready',\n visible: {\n _tag: 'Navigation',\n entry: { _tag: 'PendingCommit' },\n flight: { _tag: 'Streaming', resource: state.candidate.resource },\n generation: event.generation,\n },\n },\n };\n case 'NavigationAborted':\n if (state.candidate._tag === 'Loading') {\n return { command: null, state: { _tag: 'Ready', visible: state.visible } };\n }\n if (state.candidate._tag === 'Publishing') {\n return {\n command: { _tag: 'ReleaseRoute', resource: state.candidate.resource },\n state: { _tag: 'Ready', visible: state.visible },\n };\n }\n return {\n command: {\n _tag: 'DiscardRoute',\n rendererNavigation: state.candidate.rendererNavigation,\n resource: state.candidate.resource,\n },\n state: { _tag: 'Ready', visible: state.visible },\n };\n }\n};\n\ntype NavigationPreparation =\n | { readonly _tag: 'Handled' }\n | {\n readonly _tag: 'Rendered';\n readonly rendererNavigation: BrowserRendererNavigation;\n readonly resolvedDestination: URL;\n readonly resource: RouteResource;\n };\n\nexport const installClientRouter = Effect.gen(function* () {\n const browserRenderer = yield* BrowserRenderer;\n const navigationApi = yield* NavigationApi;\n const routeLoader = yield* RouteLoader;\n const run = yield* BrowserEffectRunner;\n const routerState = MutableRef.make<RouterState>({\n _tag: 'Ready',\n visible: { _tag: 'Settled' },\n });\n\n const dispatch = (event: RouterEvent) => {\n const transition = reduceRouterState(MutableRef.get(routerState), event);\n MutableRef.set(routerState, transition.state);\n return transition;\n };\n\n const executeRouterCommand = Effect.fnUntraced(function* (command: RouterCommand | null) {\n if (command === null) {\n return;\n }\n switch (command._tag) {\n case 'SupersedeCandidate': {\n const candidate = command.candidate;\n yield* Effect.sync(() => candidate.lifetime.abort());\n if (candidate._tag === 'Loading') {\n break;\n }\n if (candidate._tag === 'Publishing') {\n yield* candidate.resource.release;\n break;\n }\n yield* Effect.promise(() => candidate.rendererNavigation.discard()).pipe(\n Effect.ensuring(candidate.resource.release),\n );\n break;\n }\n case 'ReleaseRoute':\n yield* command.resource.release;\n break;\n case 'CacheRoute':\n yield* Effect.sync(() => command.cache(command.entry));\n break;\n case 'CacheAndReleaseRoute':\n yield* Effect.sync(() => command.resource.cache(command.entry));\n yield* command.resource.release;\n break;\n case 'DiscardRoute':\n yield* Effect.promise(() => command.rendererNavigation.discard()).pipe(\n Effect.ensuring(command.resource.release),\n );\n break;\n default:\n throw new TypeError(`Cannot execute the ${command._tag} lifecycle command here.`);\n }\n });\n\n const openDocument = (event: NavigateEvent, destination: URL) => {\n if (event.navigationType === 'traverse') {\n navigationApi.replaceDocument(destination.href);\n return;\n }\n navigationApi.navigate(destination.href, {\n history: event.navigationType === 'replace' ? 'replace' : 'push',\n info: NativeDocumentNavigationInfo,\n });\n };\n\n const onNavigate = (event: NavigateEvent) => {\n if (!isRoutedNavigation(event)) {\n return;\n }\n\n const destination = new URL(event.destination.url);\n const linkTransitionTypes = getLinkTransitionTypes(event);\n const generation: NavigationGeneration = Symbol('NavigationGeneration');\n const lifetime = new AbortController();\n const navigationSignal = AbortSignal.any([event.signal, lifetime.signal]);\n const begin = dispatch({\n _tag: 'BeginNavigation',\n generation,\n lifetime,\n });\n void run(executeRouterCommand(begin.command)).catch(() => undefined);\n // oxlint-disable-next-line effecttsgo/async-function -- Navigation handlers are native Promise boundaries.\n const handler = async (precommitController?: NavigationPrecommitController) => {\n const preparation = Promise.withResolvers<NavigationPreparation>();\n\n const navigationAction = Effect.gen(function* () {\n const resource = yield* routeLoader\n .load({\n destination: event.destination,\n navigationType: event.navigationType,\n })\n .pipe(\n Effect.onError(() =>\n Effect.sync(() => {\n dispatch({ _tag: 'FlightFailed', generation });\n }),\n ),\n );\n\n if (resource._tag === 'Document') {\n dispatch({ _tag: 'DocumentLoaded', generation });\n yield* resource.release;\n openDocument(event, destination);\n return { _tag: 'Handled' } as const;\n }\n\n const resolvedDestination = preserveRequestedHash(destination, resource.resolvedUrl);\n if (resolvedDestination.origin !== destination.origin) {\n dispatch({ _tag: 'DocumentLoaded', generation });\n yield* resource.release;\n openDocument(event, resolvedDestination);\n return { _tag: 'Handled' } as const;\n }\n\n if (\n destination.href !== resolvedDestination.href &&\n (precommitController === undefined || event.navigationType === 'traverse')\n ) {\n dispatch({ _tag: 'DocumentLoaded', generation });\n yield* resource.release;\n navigationApi.replaceDocument(resolvedDestination.href);\n return { _tag: 'Handled' } as const;\n }\n\n const transition = dispatch({ _tag: 'RouteLoaded', generation, resource });\n const command = transition.command;\n if (command?._tag === 'ReleaseRoute') {\n yield* command.resource.release;\n return { _tag: 'Handled' } as const;\n }\n if (command?._tag === 'PublishRoute') {\n const rendererNavigation = yield* Effect.sync(() => {\n let navigation!: BrowserRendererNavigation;\n startTransition(() => {\n const fromIndex =\n navigationApi.getTransition()?.from.index ??\n navigationApi.getCurrentEntry()?.index ??\n null;\n for (const type of getNavigationTransitionTypes(event, fromIndex)) {\n addTransitionType(type);\n }\n for (const type of linkTransitionTypes) {\n addTransitionType(type);\n }\n navigation = browserRenderer.navigate(command.resource.routeTree);\n });\n return navigation;\n });\n const scheduled = dispatch({\n _tag: 'RenderScheduled',\n generation: command.generation,\n rendererNavigation,\n resource: command.resource,\n });\n if (scheduled.command !== null) {\n yield* executeRouterCommand(scheduled.command);\n return { _tag: 'Handled' } as const;\n }\n return {\n _tag: 'Rendered',\n rendererNavigation,\n resolvedDestination,\n resource: command.resource,\n } as const;\n }\n\n throw new TypeError('A loaded route must be published or released.');\n });\n\n // oxlint-disable-next-line effecttsgo/async-function -- React Transition Actions are a native Promise boundary.\n startTransition(async () => {\n await run(navigationAction, { signal: navigationSignal })\n .then(preparation.resolve)\n .catch(preparation.reject);\n });\n\n const abortNavigation = Effect.suspend(() => {\n const transition = dispatch({ _tag: 'NavigationAborted', generation });\n return executeRouterCommand(transition.command);\n });\n const outcome = await preparation.promise.catch((cause) => {\n if (navigationSignal.aborted) {\n return run(abortNavigation.pipe(Effect.as({ _tag: 'Handled' } as NavigationPreparation)));\n }\n if (!event.cancelable && event.navigationType === 'traverse') {\n navigationApi.reloadDocument();\n return { _tag: 'Handled' } as NavigationPreparation;\n }\n throw cause;\n });\n if (outcome._tag === 'Handled') {\n return;\n }\n\n const { rendererNavigation, resolvedDestination, resource } = outcome;\n const waitForNavigationCommit = Effect.uninterruptibleMask((restore) =>\n restore(Effect.promise(() => rendererNavigation.committed)).pipe(\n Effect.tap(\n Effect.suspend(() => {\n const transition = dispatch({\n _tag: 'RenderCommitted',\n generation,\n });\n return executeRouterCommand(transition.command);\n }),\n ),\n Effect.onExit((exit) => (Exit.isFailure(exit) ? abortNavigation : Effect.void)),\n ),\n );\n try {\n await run(waitForNavigationCommit, { signal: navigationSignal });\n } catch (cause) {\n if (navigationSignal.aborted) {\n return;\n }\n throw cause;\n }\n\n const waitForRenderRetirement = Effect.gen(function* () {\n yield* Effect.promise(() => rendererNavigation.retired);\n dispatch({ _tag: 'RenderRetired', generation });\n }).pipe(\n // A newer generation may already be current when this render retires.\n Effect.ensuring(resource.release),\n Effect.ignore,\n );\n void run(waitForRenderRetirement).catch(() => undefined);\n\n const waitForFlightCompletion = Effect.gen(function* () {\n const flightExit = yield* Effect.exit(resource.completed);\n const transition = dispatch({\n _tag: Exit.isSuccess(flightExit) ? 'FlightCompleted' : 'FlightFailed',\n generation,\n });\n yield* executeRouterCommand(transition.command);\n });\n void run(waitForFlightCompletion).catch(() => undefined);\n\n if (destination.href !== resolvedDestination.href && precommitController !== undefined) {\n precommitController.redirect(resolvedDestination.href, { history: 'auto' });\n }\n const commitHistory = Effect.suspend(() => {\n const transition = dispatch({\n _tag: 'HistoryCommitted',\n entry: navigationApi.getCurrentEntry(),\n generation,\n });\n return executeRouterCommand(transition.command);\n });\n if (precommitController === undefined) {\n await run(commitHistory);\n } else {\n precommitController.addHandler(() => run(commitHistory));\n }\n };\n\n event.intercept(\n event.cancelable\n ? { precommitHandler: handler }\n : {\n // Browsers make some traversals non-cancelable so an application cannot trap users.\n handler,\n },\n );\n };\n\n yield* Effect.acquireRelease(\n Effect.sync(() => navigationApi.subscribe(onNavigate)),\n (unsubscribe) => Effect.sync(unsubscribe),\n );\n});\n"],"names":["Effect","Exit","MutableRef","addTransitionType","startTransition","BrowserEffectRunner","BrowserRenderer","NavigationApi","isRoutedNavigation","NativeDocumentNavigationInfo","preserveRequestedHash","RouteLoader","reservedTransitionTypes","Set","isApplicationTransitionType","type","getLinkTransitionTypes","event","HTMLAnchorElement","types","getNavigationTransitionTypes","fromIndex","reduceRouterState","state","visible","TypeError","nextState","installClientRouter","browserRenderer","navigationApi","routeLoader","run","routerState","dispatch","transition","executeRouterCommand","command","candidate","openDocument","destination","onNavigate","URL","linkTransitionTypes","generation","Symbol","lifetime","AbortController","navigationSignal","AbortSignal","begin","undefined","handler","precommitController","preparation","Promise","navigationAction","resource","resolvedDestination","rendererNavigation","navigation","scheduled","abortNavigation","outcome","cause","waitForNavigationCommit","restore","exit","waitForRenderRetirement","waitForFlightCompletion","flightExit","commitHistory","unsubscribe"],"mappings":";;;;;;;;;;;;;;;AAAkD;AACS;AAEG;AACuB;AACpC;AAKnB;AAC+B;AAK7D,MAAMY,uBAAuBA,GAAG,IAAIC,IAAI;IAAC;IAAc;IAAmB;CAAc;AAExF,MAAMC,2BAA2BA,GAAG,CAACC,OACnC,CAACH,uBAAuBA,CAAC,GAAG,CAACG,SAAS,CAACA,KAAK,UAAU,CAAC;AAEzD,MAAMC,sBAAsBA,GAAG,CAACC;IAC9B,IACGA,MAAM,cAAc,KAAK,UAAUA,MAAM,cAAc,KAAK,aAC7D,CAAEA,CAAAA,MAAM,aAAa,YAAYC,iBAAgB,GACjD;QACA,OAAO,EAAE;IACX;IACA,MAAMC,QAAQF,MAAM,aAAa,CAAC,OAAO,CAAC,sBAAsB,EAAE,MAAM,WAAW,EAAE;IACrF,OAAO;WAAI,IAAIJ,IAAIM,MAAM,MAAM,CAACL,2BAA2BA;KAAG;AAChE;AAEA,MAAMM,4BAA4BA,GAAG,CACnCH,OACAI;IAEA,MAAMF,QAAQ;QACZ;QACA,CAAC,WAAW,EAAEF,MAAM,cAAc,EAAE;WAChCA,MAAM,qBAAqB,GAAG;YAAC;SAAkC,GAAG,EAAE;KAC3E;IACD,IAAIA,MAAM,cAAc,KAAK,QAAQ;QACnC,OAAO;eAAIE;YAAO;SAAqB;IACzC;IACA,IAAIF,MAAM,cAAc,KAAK,YAAY;QACvC,OAAOE;IACT;IAEA,IAAIE,cAAc,QAAQA,cAAcJ,MAAM,WAAW,CAAC,KAAK,EAAE;QAC/D,OAAOE;IACT;IACA,OAAO;WACFA;QACHF,MAAM,WAAW,CAAC,KAAK,GAAGI,YAAY,wBAAwB;KAC/D;AACH;AA4GA,MAAMC,iBAAiBA,GAAG,CAACC,OAAoBN;IAC7C,IAAIM,MAAM,OAAO,CAAC,IAAI,KAAK,gBAAgBA,MAAM,OAAO,CAAC,UAAU,KAAKN,MAAM,UAAU,EAAE;QACxF,MAAMO,UAAUD,MAAM,OAAO;QAC7B,OAAQN,MAAM,IAAI;YAChB,KAAK;gBACH,OAAO;oBACL,SAAS;oBACT,OAAO;wBAAE,GAAGM,KAAK;wBAAE,SAAS;4BAAE,MAAM;wBAAU;oBAAE;gBAClD;YACF,KAAK;gBACH,IAAIC,QAAQ,KAAK,CAAC,IAAI,KAAK,aAAa;oBACtC,MAAM,IAAIC,UAAU;gBACtB;gBACA,IAAID,QAAQ,MAAM,CAAC,IAAI,KAAK,aAAa;oBACvC,OAAO;wBACL,SAAS;wBACT,OAAO;4BACL,GAAGD,KAAK;4BACR,SAAS;gCACP,GAAGC,OAAO;gCACV,OAAO;oCAAE,MAAM;oCAAa,OAAOP,MAAM,KAAK;gCAAC;4BACjD;wBACF;oBACF;gBACF;gBACA,OAAO;oBACL,SACEA,MAAM,KAAK,KAAK,OACZ,OACA;wBAAE,MAAM;wBAAc,OAAOO,QAAQ,MAAM,CAAC,KAAK;wBAAE,OAAOP,MAAM,KAAK;oBAAC;oBAC5E,OAAO;wBAAE,GAAGM,KAAK;wBAAE,SAAS;4BAAE,MAAM;wBAAU;oBAAE;gBAClD;YACF,KAAK;gBACH,IAAIC,QAAQ,MAAM,CAAC,IAAI,KAAK,aAAa;oBACvC,MAAM,IAAIC,UAAU;gBACtB;gBACA,IAAID,QAAQ,KAAK,CAAC,IAAI,KAAK,iBAAiB;oBAC1C,OAAO;wBACL,SAAS;4BAAE,MAAM;4BAAgB,UAAUA,QAAQ,MAAM,CAAC,QAAQ;wBAAC;wBACnE,OAAO;4BACL,GAAGD,KAAK;4BACR,SAAS;gCACP,GAAGC,OAAO;gCACV,QAAQ;oCAAE,MAAM;oCAAa,OAAOA,QAAQ,MAAM,CAAC,QAAQ,CAAC,KAAK;gCAAC;4BACpE;wBACF;oBACF;gBACF;gBACA,OAAO;oBACL,SACEA,QAAQ,KAAK,CAAC,KAAK,KAAK,OACpB;wBAAE,MAAM;wBAAgB,UAAUA,QAAQ,MAAM,CAAC,QAAQ;oBAAC,IAC1D;wBACE,MAAM;wBACN,OAAOA,QAAQ,KAAK,CAAC,KAAK;wBAC1B,UAAUA,QAAQ,MAAM,CAAC,QAAQ;oBACnC;oBACN,OAAO;wBAAE,GAAGD,KAAK;wBAAE,SAAS;4BAAE,MAAM;wBAAU;oBAAE;gBAClD;YACF,KAAK;gBACH,IAAIC,QAAQ,MAAM,CAAC,IAAI,KAAK,aAAa;oBACvC,MAAM,IAAIC,UAAU;gBACtB;gBACA,OAAO;oBACL,SAAS;wBAAE,MAAM;wBAAgB,UAAUD,QAAQ,MAAM,CAAC,QAAQ;oBAAC;oBACnE,OAAO;wBAAE,GAAGD,KAAK;wBAAE,SAAS;4BAAE,MAAM;wBAAU;oBAAE;gBAClD;QACJ;IACF;IAEA,IACEN,MAAM,IAAI,KAAK,mBACfA,MAAM,IAAI,KAAK,sBACfA,MAAM,IAAI,KAAK,mBACf;QACA,OAAO;YAAE,SAAS;YAAMM;QAAM;IAChC;IAEA,IAAIN,MAAM,IAAI,KAAK,mBAAmB;QACpC,MAAMS,YAAyB;YAC7B,MAAM;YACN,WAAW;gBACT,MAAM;gBACN,YAAYT,MAAM,UAAU;gBAC5B,UAAUA,MAAM,QAAQ;YAC1B;YACA,SAASM,MAAM,OAAO;QACxB;QACA,IAAIA,MAAM,IAAI,KAAK,SAAS;YAC1B,OAAO;gBAAE,SAAS;gBAAM,OAAOG;YAAU;QAC3C;QACA,OAAO;YACL,SAAS;gBAAE,MAAM;gBAAsB,WAAWH,MAAM,SAAS;YAAC;YAClE,OAAOG;QACT;IACF;IAEA,IAAIH,MAAM,IAAI,KAAK,WAAWA,MAAM,SAAS,CAAC,UAAU,KAAKN,MAAM,UAAU,EAAE;QAC7E,OAAQA,MAAM,IAAI;YAChB,KAAK;gBACH,OAAO;oBAAE,SAAS;wBAAE,MAAM;wBAAgB,UAAUA,MAAM,QAAQ;oBAAC;oBAAGM;gBAAM;YAC9E,KAAK;gBACH,OAAO;oBACL,SAAS;wBACP,MAAM;wBACN,oBAAoBN,MAAM,kBAAkB;wBAC5C,UAAUA,MAAM,QAAQ;oBAC1B;oBACAM;gBACF;YACF;gBACE,OAAO;oBAAE,SAAS;oBAAMA;gBAAM;QAClC;IACF;IAEA,OAAQN,MAAM,IAAI;QAChB,KAAK;QACL,KAAK;YACH,IAAIM,MAAM,SAAS,CAAC,IAAI,KAAK,WAAW;gBACtC,MAAM,IAAIE,UAAU,GAAGR,MAAM,IAAI,CAAC,eAAe,EAAEM,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5E;YACA,OAAO;gBAAE,SAAS;gBAAM,OAAO;oBAAE,MAAM;oBAAS,SAASA,MAAM,OAAO;gBAAC;YAAE;QAC3E,KAAK;YACH,IAAIA,MAAM,SAAS,CAAC,IAAI,KAAK,WAAW;gBACtC,MAAM,IAAIE,UAAU,CAAC,0BAA0B,EAAEF,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAC1E;YACA,OAAO;gBACL,SAAS;oBACP,MAAM;oBACN,YAAYN,MAAM,UAAU;oBAC5B,UAAUA,MAAM,QAAQ;gBAC1B;gBACA,OAAO;oBACL,MAAM;oBACN,WAAW;wBACT,MAAM;wBACN,YAAYA,MAAM,UAAU;wBAC5B,UAAUM,MAAM,SAAS,CAAC,QAAQ;wBAClC,UAAUN,MAAM,QAAQ;oBAC1B;oBACA,SAASM,MAAM,OAAO;gBACxB;YACF;QACF,KAAK;YACH,IAAIA,MAAM,SAAS,CAAC,IAAI,KAAK,cAAc;gBACzC,MAAM,IAAIE,UAAU,CAAC,8BAA8B,EAAEF,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAC9E;YACA,IAAIA,MAAM,SAAS,CAAC,QAAQ,KAAKN,MAAM,QAAQ,EAAE;gBAC/C,MAAM,IAAIQ,UAAU;YACtB;YACA,OAAO;gBACL,SAAS;gBACT,OAAO;oBACL,MAAM;oBACN,WAAW;wBACT,MAAM;wBACN,YAAYR,MAAM,UAAU;wBAC5B,UAAUM,MAAM,SAAS,CAAC,QAAQ;wBAClC,oBAAoBN,MAAM,kBAAkB;wBAC5C,UAAUA,MAAM,QAAQ;oBAC1B;oBACA,SAASM,MAAM,OAAO;gBACxB;YACF;QACF,KAAK;YACH,IAAIA,MAAM,SAAS,CAAC,IAAI,KAAK,aAAa;gBACxC,MAAM,IAAIE,UAAU,CAAC,8BAA8B,EAAEF,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAC9E;YACA,OAAO;gBACL,SAAS;gBACT,OAAO;oBACL,MAAM;oBACN,SAAS;wBACP,MAAM;wBACN,OAAO;4BAAE,MAAM;wBAAgB;wBAC/B,QAAQ;4BAAE,MAAM;4BAAa,UAAUA,MAAM,SAAS,CAAC,QAAQ;wBAAC;wBAChE,YAAYN,MAAM,UAAU;oBAC9B;gBACF;YACF;QACF,KAAK;YACH,IAAIM,MAAM,SAAS,CAAC,IAAI,KAAK,WAAW;gBACtC,OAAO;oBAAE,SAAS;oBAAM,OAAO;wBAAE,MAAM;wBAAS,SAASA,MAAM,OAAO;oBAAC;gBAAE;YAC3E;YACA,IAAIA,MAAM,SAAS,CAAC,IAAI,KAAK,cAAc;gBACzC,OAAO;oBACL,SAAS;wBAAE,MAAM;wBAAgB,UAAUA,MAAM,SAAS,CAAC,QAAQ;oBAAC;oBACpE,OAAO;wBAAE,MAAM;wBAAS,SAASA,MAAM,OAAO;oBAAC;gBACjD;YACF;YACA,OAAO;gBACL,SAAS;oBACP,MAAM;oBACN,oBAAoBA,MAAM,SAAS,CAAC,kBAAkB;oBACtD,UAAUA,MAAM,SAAS,CAAC,QAAQ;gBACpC;gBACA,OAAO;oBAAE,MAAM;oBAAS,SAASA,MAAM,OAAO;gBAAC;YACjD;IACJ;AACF;AAWO,MAAMI,mBAAmBA,GAAG3B,UAAU,CAAC;IAC5C,MAAM4B,kBAAkB,OAAOtB,eAAeA;IAC9C,MAAMuB,gBAAgB,OAAOtB,aAAaA;IAC1C,MAAMuB,cAAc,OAAOnB,WAAWA;IACtC,MAAMoB,MAAM,OAAO1B,mBAAmBA;IACtC,MAAM2B,cAAc9B,eAAe,CAAc;QAC/C,MAAM;QACN,SAAS;YAAE,MAAM;QAAU;IAC7B;IAEA,MAAM+B,WAAW,CAAChB;QAChB,MAAMiB,aAAaZ,iBAAiBA,CAACpB,cAAc,CAAC8B,cAAcf;QAClEf,cAAc,CAAC8B,aAAaE,WAAW,KAAK;QAC5C,OAAOA;IACT;IAEA,MAAMC,uBAAuBnC,iBAAiB,CAAC,UAAWoC,OAA6B;QACrF,IAAIA,YAAY,MAAM;YACpB;QACF;QACA,OAAQA,QAAQ,IAAI;YAClB,KAAK;gBAAsB;oBACzB,MAAMC,YAAYD,QAAQ,SAAS;oBACnC,OAAOpC,WAAW,CAAC,IAAMqC,UAAU,QAAQ,CAAC,KAAK;oBACjD,IAAIA,UAAU,IAAI,KAAK,WAAW;wBAChC;oBACF;oBACA,IAAIA,UAAU,IAAI,KAAK,cAAc;wBACnC,OAAOA,UAAU,QAAQ,CAAC,OAAO;wBACjC;oBACF;oBACA,OAAOrC,cAAc,CAAC,IAAMqC,UAAU,kBAAkB,CAAC,OAAO,IAAI,IAAI,CACtErC,eAAe,CAACqC,UAAU,QAAQ,CAAC,OAAO;oBAE5C;gBACF;YACA,KAAK;gBACH,OAAOD,QAAQ,QAAQ,CAAC,OAAO;gBAC/B;YACF,KAAK;gBACH,OAAOpC,WAAW,CAAC,IAAMoC,QAAQ,KAAK,CAACA,QAAQ,KAAK;gBACpD;YACF,KAAK;gBACH,OAAOpC,WAAW,CAAC,IAAMoC,QAAQ,QAAQ,CAAC,KAAK,CAACA,QAAQ,KAAK;gBAC7D,OAAOA,QAAQ,QAAQ,CAAC,OAAO;gBAC/B;YACF,KAAK;gBACH,OAAOpC,cAAc,CAAC,IAAMoC,QAAQ,kBAAkB,CAAC,OAAO,IAAI,IAAI,CACpEpC,eAAe,CAACoC,QAAQ,QAAQ,CAAC,OAAO;gBAE1C;YACF;gBACE,MAAM,IAAIX,UAAU,CAAC,mBAAmB,EAAEW,QAAQ,IAAI,CAAC,wBAAwB,CAAC;QACpF;IACF;IAEA,MAAME,eAAe,CAACrB,OAAsBsB;QAC1C,IAAItB,MAAM,cAAc,KAAK,YAAY;YACvCY,cAAc,eAAe,CAACU,YAAY,IAAI;YAC9C;QACF;QACAV,cAAc,QAAQ,CAACU,YAAY,IAAI,EAAE;YACvC,SAAStB,MAAM,cAAc,KAAK,YAAY,YAAY;YAC1D,MAAMR,4BAA4BA;QACpC;IACF;IAEA,MAAM+B,aAAa,CAACvB;QAClB,IAAI,CAACT,kBAAkBA,CAACS,QAAQ;YAC9B;QACF;QAEA,MAAMsB,cAAc,IAAIE,IAAIxB,MAAM,WAAW,CAAC,GAAG;QACjD,MAAMyB,sBAAsB1B,sBAAsBA,CAACC;QACnD,MAAM0B,aAAmCC,OAAO;QAChD,MAAMC,WAAW,IAAIC;QACrB,MAAMC,mBAAmBC,YAAY,GAAG,CAAC;YAAC/B,MAAM,MAAM;YAAE4B,SAAS,MAAM;SAAC;QACxE,MAAMI,QAAQhB,SAAS;YACrB,MAAM;YACNU;YACAE;QACF;QACA,KAAKd,IAAII,qBAAqBc,MAAM,OAAO,GAAG,KAAK,CAAC,IAAMC;QAC1D,2GAA2G;QAC3G,MAAMC,UAAU,OAAOC;YACrB,MAAMC,cAAcC,QAAQ,aAAa;YAEzC,MAAMC,mBAAmBvD,UAAU,CAAC;gBAClC,MAAMwD,WAAW,OAAO1B,YACrB,IAAI,CAAC;oBACJ,aAAab,MAAM,WAAW;oBAC9B,gBAAgBA,MAAM,cAAc;gBACtC,GACC,IAAI,CACHjB,cAAc,CAAC,IACbA,WAAW,CAAC;wBACViC,SAAS;4BAAE,MAAM;4BAAgBU;wBAAW;oBAC9C;gBAIN,IAAIa,SAAS,IAAI,KAAK,YAAY;oBAChCvB,SAAS;wBAAE,MAAM;wBAAkBU;oBAAW;oBAC9C,OAAOa,SAAS,OAAO;oBACvBlB,aAAarB,OAAOsB;oBACpB,OAAO;wBAAE,MAAM;oBAAU;gBAC3B;gBAEA,MAAMkB,sBAAsB/C,qBAAqBA,CAAC6B,aAAaiB,SAAS,WAAW;gBACnF,IAAIC,oBAAoB,MAAM,KAAKlB,YAAY,MAAM,EAAE;oBACrDN,SAAS;wBAAE,MAAM;wBAAkBU;oBAAW;oBAC9C,OAAOa,SAAS,OAAO;oBACvBlB,aAAarB,OAAOwC;oBACpB,OAAO;wBAAE,MAAM;oBAAU;gBAC3B;gBAEA,IACElB,YAAY,IAAI,KAAKkB,oBAAoB,IAAI,IAC5CL,CAAAA,wBAAwBF,aAAajC,MAAM,cAAc,KAAK,UAAS,GACxE;oBACAgB,SAAS;wBAAE,MAAM;wBAAkBU;oBAAW;oBAC9C,OAAOa,SAAS,OAAO;oBACvB3B,cAAc,eAAe,CAAC4B,oBAAoB,IAAI;oBACtD,OAAO;wBAAE,MAAM;oBAAU;gBAC3B;gBAEA,MAAMvB,aAAaD,SAAS;oBAAE,MAAM;oBAAeU;oBAAYa;gBAAS;gBACxE,MAAMpB,UAAUF,WAAW,OAAO;gBAClC,IAAIE,SAAS,SAAS,gBAAgB;oBACpC,OAAOA,QAAQ,QAAQ,CAAC,OAAO;oBAC/B,OAAO;wBAAE,MAAM;oBAAU;gBAC3B;gBACA,IAAIA,SAAS,SAAS,gBAAgB;oBACpC,MAAMsB,qBAAqB,OAAO1D,WAAW,CAAC;wBAC5C,IAAI2D;wBACJvD,eAAeA,CAAC;4BACd,MAAMiB,YACJQ,cAAc,aAAa,IAAI,KAAK,SACpCA,cAAc,eAAe,IAAI,SACjC;4BACF,KAAK,MAAMd,QAAQK,4BAA4BA,CAACH,OAAOI,WAAY;gCACjElB,iBAAiBA,CAACY;4BACpB;4BACA,KAAK,MAAMA,QAAQ2B,oBAAqB;gCACtCvC,iBAAiBA,CAACY;4BACpB;4BACA4C,aAAa/B,gBAAgB,QAAQ,CAACQ,QAAQ,QAAQ,CAAC,SAAS;wBAClE;wBACA,OAAOuB;oBACT;oBACA,MAAMC,YAAY3B,SAAS;wBACzB,MAAM;wBACN,YAAYG,QAAQ,UAAU;wBAC9BsB;wBACA,UAAUtB,QAAQ,QAAQ;oBAC5B;oBACA,IAAIwB,UAAU,OAAO,KAAK,MAAM;wBAC9B,OAAOzB,qBAAqByB,UAAU,OAAO;wBAC7C,OAAO;4BAAE,MAAM;wBAAU;oBAC3B;oBACA,OAAO;wBACL,MAAM;wBACNF;wBACAD;wBACA,UAAUrB,QAAQ,QAAQ;oBAC5B;gBACF;gBAEA,MAAM,IAAIX,UAAU;YACtB;YAEA,gHAAgH;YAChHrB,eAAeA,CAAC;gBACd,MAAM2B,IAAIwB,kBAAkB;oBAAE,QAAQR;gBAAiB,GACpD,IAAI,CAACM,YAAY,OAAO,EACxB,KAAK,CAACA,YAAY,MAAM;YAC7B;YAEA,MAAMQ,kBAAkB7D,cAAc,CAAC;gBACrC,MAAMkC,aAAaD,SAAS;oBAAE,MAAM;oBAAqBU;gBAAW;gBACpE,OAAOR,qBAAqBD,WAAW,OAAO;YAChD;YACA,MAAM4B,UAAU,MAAMT,YAAY,OAAO,CAAC,KAAK,CAAC,CAACU;gBAC/C,IAAIhB,iBAAiB,OAAO,EAAE;oBAC5B,OAAOhB,IAAI8B,gBAAgB,IAAI,CAAC7D,SAAS,CAAC;wBAAE,MAAM;oBAAU;gBAC9D;gBACA,IAAI,CAACiB,MAAM,UAAU,IAAIA,MAAM,cAAc,KAAK,YAAY;oBAC5DY,cAAc,cAAc;oBAC5B,OAAO;wBAAE,MAAM;oBAAU;gBAC3B;gBACA,MAAMkC;YACR;YACA,IAAID,QAAQ,IAAI,KAAK,WAAW;gBAC9B;YACF;YAEA,MAAM,EAAEJ,kBAAkB,EAAED,mBAAmB,EAAED,QAAQ,EAAE,GAAGM;YAC9D,MAAME,0BAA0BhE,0BAA0B,CAAC,CAACiE,UAC1DA,QAAQjE,cAAc,CAAC,IAAM0D,mBAAmB,SAAS,GAAG,IAAI,CAC9D1D,UAAU,CACRA,cAAc,CAAC;oBACb,MAAMkC,aAAaD,SAAS;wBAC1B,MAAM;wBACNU;oBACF;oBACA,OAAOR,qBAAqBD,WAAW,OAAO;gBAChD,KAEFlC,aAAa,CAAC,CAACkE,OAAUjE,cAAc,CAACiE,QAAQL,kBAAkB7D,cAAW;YAGjF,IAAI;gBACF,MAAM+B,IAAIiC,yBAAyB;oBAAE,QAAQjB;gBAAiB;YAChE,EAAE,OAAOgB,OAAO;gBACd,IAAIhB,iBAAiB,OAAO,EAAE;oBAC5B;gBACF;gBACA,MAAMgB;YACR;YAEA,MAAMI,0BAA0BnE,UAAU,CAAC;gBACzC,OAAOA,cAAc,CAAC,IAAM0D,mBAAmB,OAAO;gBACtDzB,SAAS;oBAAE,MAAM;oBAAiBU;gBAAW;YAC/C,GAAG,IAAI,CACL,sEAAsE;YACtE3C,eAAe,CAACwD,SAAS,OAAO,GAChCxD,aAAa;YAEf,KAAK+B,IAAIoC,yBAAyB,KAAK,CAAC,IAAMjB;YAE9C,MAAMkB,0BAA0BpE,UAAU,CAAC;gBACzC,MAAMqE,aAAa,OAAOrE,WAAW,CAACwD,SAAS,SAAS;gBACxD,MAAMtB,aAAaD,SAAS;oBAC1B,MAAMhC,cAAc,CAACoE,cAAc,oBAAoB;oBACvD1B;gBACF;gBACA,OAAOR,qBAAqBD,WAAW,OAAO;YAChD;YACA,KAAKH,IAAIqC,yBAAyB,KAAK,CAAC,IAAMlB;YAE9C,IAAIX,YAAY,IAAI,KAAKkB,oBAAoB,IAAI,IAAIL,wBAAwBF,WAAW;gBACtFE,oBAAoB,QAAQ,CAACK,oBAAoB,IAAI,EAAE;oBAAE,SAAS;gBAAO;YAC3E;YACA,MAAMa,gBAAgBtE,cAAc,CAAC;gBACnC,MAAMkC,aAAaD,SAAS;oBAC1B,MAAM;oBACN,OAAOJ,cAAc,eAAe;oBACpCc;gBACF;gBACA,OAAOR,qBAAqBD,WAAW,OAAO;YAChD;YACA,IAAIkB,wBAAwBF,WAAW;gBACrC,MAAMnB,IAAIuC;YACZ,OAAO;gBACLlB,oBAAoB,UAAU,CAAC,IAAMrB,IAAIuC;YAC3C;QACF;QAEArD,MAAM,SAAS,CACbA,MAAM,UAAU,GACZ;YAAE,kBAAkBkC;QAAQ,IAC5B;YACE,oFAAoF;YACpFA;QACF;IAER;IAEA,OAAOnD,qBAAqB,CAC1BA,WAAW,CAAC,IAAM6B,cAAc,SAAS,CAACW,cAC1C,CAAC+B,cAAgBvE,WAAW,CAACuE;AAEjC,GAAG"}
@@ -88,15 +88,14 @@ class FlightClient extends Context.Service()('ersc/client/FlightClient', {
88
88
  reason: 'UnexpectedResponse'
89
89
  });
90
90
  }
91
- const contentLocation = response.headers['content-location'];
92
- if (contentLocation === undefined) {
91
+ if (response.url === '') {
93
92
  return yield* new FlightLoadError({
94
- cause: new Error('Expected the Flight response to include a Content-Location header.'),
93
+ cause: new Error('Expected the Flight response to include a resolved URL.'),
95
94
  reason: 'UnexpectedResponse'
96
95
  });
97
96
  }
98
97
  const resolvedUrl = yield* Effect["try"]({
99
- try: ()=>new URL(contentLocation, flightRequest.destination),
98
+ try: ()=>new URL(response.url),
100
99
  catch: (cause)=>new FlightLoadError({
101
100
  cause,
102
101
  reason: 'UnexpectedResponse'