effective-rsc 0.1.2 → 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.
- package/LLMS.md +85 -0
- package/README.md +14 -8
- package/dist/application/routes.d.ts +10 -10
- package/dist/application/routes.js.map +1 -1
- package/dist/build/build.d.ts +4 -2
- package/dist/build/build.js +19 -2
- package/dist/build/build.js.map +1 -1
- package/dist/build/deployment.d.ts +10 -0
- package/dist/build/deployment.js +59 -0
- package/dist/build/deployment.js.map +1 -0
- package/dist/build/dev.d.ts +4 -4
- package/dist/build/dev.js +22 -7
- package/dist/build/dev.js.map +1 -1
- package/dist/build/hook.d.ts +8 -0
- package/dist/build/hook.js +5 -0
- package/dist/build/hook.js.map +1 -0
- package/dist/build/rspack.js +1 -1
- package/dist/build/rspack.js.map +1 -1
- package/dist/cli.js +13 -24
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-renderer.d.ts +25 -25
- package/dist/client/browser-renderer.js +80 -94
- package/dist/client/browser-renderer.js.map +1 -1
- package/dist/client/call-server.js +7 -5
- package/dist/client/call-server.js.map +1 -1
- package/dist/client/client-router.js +23 -7
- package/dist/client/client-router.js.map +1 -1
- package/dist/client/flight-client.js +3 -4
- package/dist/client/flight-client.js.map +1 -1
- package/dist/client/react-dom-renderer.js +2 -1
- package/dist/client/react-dom-renderer.js.map +1 -1
- package/dist/client/route-refresh.d.ts +2 -2
- package/dist/client/route-refresh.js +54 -39
- package/dist/client/route-refresh.js.map +1 -1
- package/dist/dev/panel.js +14 -14
- package/dist/dev/panel.js.map +1 -1
- package/dist/server/application.d.ts +2 -1
- package/dist/server/application.js +8 -6
- package/dist/server/application.js.map +1 -1
- package/dist/server/html-renderer.js +12 -11
- package/dist/server/html-renderer.js.map +1 -1
- package/dist/server/serve.d.ts +7 -0
- package/dist/server/serve.js +31 -0
- package/dist/server/serve.js.map +1 -0
- package/dist/server/start.d.ts +3 -0
- package/dist/server/start.js +24 -0
- package/dist/server/start.js.map +1 -0
- package/docs/02-guides/06-deploying-to-vercel/index.md +34 -0
- package/docs/02-guides/index.md +1 -0
- package/docs/03-advanced/02-client-navigation/index.md +17 -0
- package/docs/03-advanced/04-production-startup/01_server.ts +11 -0
- package/docs/03-advanced/04-production-startup/index.md +22 -0
- package/docs/03-advanced/index.md +1 -0
- package/package.json +27 -20
|
@@ -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
|
|
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:
|
|
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
|
-
|
|
557
|
+
dispatch({
|
|
542
558
|
_tag: 'RenderRetired',
|
|
543
559
|
generation
|
|
544
560
|
});
|
|
545
|
-
|
|
546
|
-
|
|
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":";;;;;;;;;;;;;;;AAAkD;AACS;AAEG;AACuB;AACpC;AAKnB;AAC+B;AAK7D,MAAMY,4BAA4BA,GAAG,CACnCC,OACAC;IAEA,MAAMC,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,IAAID,cAAc,QAAQA,cAAcD,MAAM,WAAW,CAAC,KAAK,EAAE;QAC/D,OAAOE;IACT;IACA,OAAO;WACFA;QACHF,MAAM,WAAW,CAAC,KAAK,GAAGC,YAAY,wBAAwB;KAC/D;AACH;AA4GA,MAAME,iBAAiBA,GAAG,CAACC,OAAoBJ;IAC7C,IAAII,MAAM,OAAO,CAAC,IAAI,KAAK,gBAAgBA,MAAM,OAAO,CAAC,UAAU,KAAKJ,MAAM,UAAU,EAAE;QACxF,MAAMK,UAAUD,MAAM,OAAO;QAC7B,OAAQJ,MAAM,IAAI;YAChB,KAAK;gBACH,OAAO;oBACL,SACEK,QAAQ,MAAM,CAAC,IAAI,KAAK,cACpB;wBAAE,MAAM;wBAAgB,UAAUA,QAAQ,MAAM,CAAC,QAAQ;oBAAC,IAC1D;oBACN,OAAO;wBAAE,GAAGD,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,OAAOL,MAAM,KAAK;gCAAC;4BACjD;wBACF;oBACF;gBACF;gBACA,OAAO;oBACL,SACEA,MAAM,KAAK,KAAK,OACZ,OACA;wBAAE,MAAM;wBAAc,OAAOK,QAAQ,MAAM,CAAC,KAAK;wBAAE,OAAOL,MAAM,KAAK;oBAAC;oBAC5E,OAAO;wBAAE,GAAGI,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,IACEJ,MAAM,IAAI,KAAK,mBACfA,MAAM,IAAI,KAAK,sBACfA,MAAM,IAAI,KAAK,mBACf;QACA,OAAO;YAAE,SAAS;YAAMI;QAAM;IAChC;IAEA,IAAIJ,MAAM,IAAI,KAAK,mBAAmB;QACpC,MAAMO,YAAyB;YAC7B,MAAM;YACN,WAAW;gBACT,MAAM;gBACN,YAAYP,MAAM,UAAU;gBAC5B,UAAUA,MAAM,QAAQ;YAC1B;YACA,SAASI,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,KAAKJ,MAAM,UAAU,EAAE;QAC7E,OAAQA,MAAM,IAAI;YAChB,KAAK;gBACH,OAAO;oBAAE,SAAS;wBAAE,MAAM;wBAAgB,UAAUA,MAAM,QAAQ;oBAAC;oBAAGI;gBAAM;YAC9E,KAAK;gBACH,OAAO;oBACL,SAAS;wBACP,MAAM;wBACN,oBAAoBJ,MAAM,kBAAkB;wBAC5C,UAAUA,MAAM,QAAQ;oBAC1B;oBACAI;gBACF;YACF;gBACE,OAAO;oBAAE,SAAS;oBAAMA;gBAAM;QAClC;IACF;IAEA,OAAQJ,MAAM,IAAI;QAChB,KAAK;QACL,KAAK;YACH,IAAII,MAAM,SAAS,CAAC,IAAI,KAAK,WAAW;gBACtC,MAAM,IAAIE,UAAU,GAAGN,MAAM,IAAI,CAAC,eAAe,EAAEI,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,YAAYJ,MAAM,UAAU;oBAC5B,UAAUA,MAAM,QAAQ;gBAC1B;gBACA,OAAO;oBACL,MAAM;oBACN,WAAW;wBACT,MAAM;wBACN,YAAYA,MAAM,UAAU;wBAC5B,UAAUI,MAAM,SAAS,CAAC,QAAQ;wBAClC,UAAUJ,MAAM,QAAQ;oBAC1B;oBACA,SAASI,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,KAAKJ,MAAM,QAAQ,EAAE;gBAC/C,MAAM,IAAIM,UAAU;YACtB;YACA,OAAO;gBACL,SAAS;gBACT,OAAO;oBACL,MAAM;oBACN,WAAW;wBACT,MAAM;wBACN,YAAYN,MAAM,UAAU;wBAC5B,UAAUI,MAAM,SAAS,CAAC,QAAQ;wBAClC,oBAAoBJ,MAAM,kBAAkB;wBAC5C,UAAUA,MAAM,QAAQ;oBAC1B;oBACA,SAASI,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,YAAYJ,MAAM,UAAU;oBAC9B;gBACF;YACF;QACF,KAAK;YACH,IAAII,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,GAAGrB,UAAU,CAAC;IAC5C,MAAMsB,kBAAkB,OAAOhB,eAAeA;IAC9C,MAAMiB,gBAAgB,OAAOhB,aAAaA;IAC1C,MAAMiB,cAAc,OAAOb,WAAWA;IACtC,MAAMc,MAAM,OAAOpB,mBAAmBA;IACtC,MAAMqB,cAAcxB,eAAe,CAAc;QAC/C,MAAM;QACN,SAAS;YAAE,MAAM;QAAU;IAC7B;IAEA,MAAMyB,WAAW,CAACd;QAChB,MAAMe,aAAaZ,iBAAiBA,CAACd,cAAc,CAACwB,cAAcb;QAClEX,cAAc,CAACwB,aAAaE,WAAW,KAAK;QAC5C,OAAOA;IACT;IAEA,MAAMC,uBAAuB7B,iBAAiB,CAAC,UAAW8B,OAA6B;QACrF,IAAIA,YAAY,MAAM;YACpB;QACF;QACA,OAAQA,QAAQ,IAAI;YAClB,KAAK;gBAAsB;oBACzB,MAAMC,YAAYD,QAAQ,SAAS;oBACnC,OAAO9B,WAAW,CAAC,IAAM+B,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,OAAO/B,cAAc,CAAC,IAAM+B,UAAU,kBAAkB,CAAC,OAAO,IAAI,IAAI,CACtE/B,eAAe,CAAC+B,UAAU,QAAQ,CAAC,OAAO;oBAE5C;gBACF;YACA,KAAK;gBACH,OAAOD,QAAQ,QAAQ,CAAC,OAAO;gBAC/B;YACF,KAAK;gBACH,OAAO9B,WAAW,CAAC,IAAM8B,QAAQ,KAAK,CAACA,QAAQ,KAAK;gBACpD;YACF,KAAK;gBACH,OAAO9B,WAAW,CAAC,IAAM8B,QAAQ,QAAQ,CAAC,KAAK,CAACA,QAAQ,KAAK;gBAC7D,OAAOA,QAAQ,QAAQ,CAAC,OAAO;gBAC/B;YACF,KAAK;gBACH,OAAO9B,cAAc,CAAC,IAAM8B,QAAQ,kBAAkB,CAAC,OAAO,IAAI,IAAI,CACpE9B,eAAe,CAAC8B,QAAQ,QAAQ,CAAC,OAAO;gBAE1C;YACF;gBACE,MAAM,IAAIX,UAAU,CAAC,mBAAmB,EAAEW,QAAQ,IAAI,CAAC,wBAAwB,CAAC;QACpF;IACF;IAEA,MAAME,eAAe,CAACnB,OAAsBoB;QAC1C,IAAIpB,MAAM,cAAc,KAAK,YAAY;YACvCU,cAAc,eAAe,CAACU,YAAY,IAAI;YAC9C;QACF;QACAV,cAAc,QAAQ,CAACU,YAAY,IAAI,EAAE;YACvC,SAASpB,MAAM,cAAc,KAAK,YAAY,YAAY;YAC1D,MAAMJ,4BAA4BA;QACpC;IACF;IAEA,MAAMyB,aAAa,CAACrB;QAClB,IAAI,CAACL,kBAAkBA,CAACK,QAAQ;YAC9B;QACF;QAEA,MAAMoB,cAAc,IAAIE,IAAItB,MAAM,WAAW,CAAC,GAAG;QACjD,MAAMuB,aAAmCC,OAAO;QAChD,MAAMC,WAAW,IAAIC;QACrB,MAAMC,mBAAmBC,YAAY,GAAG,CAAC;YAAC5B,MAAM,MAAM;YAAEyB,SAAS,MAAM;SAAC;QACxE,MAAMI,QAAQf,SAAS;YACrB,MAAM;YACNS;YACAE;QACF;QACA,KAAKb,IAAII,qBAAqBa,MAAM,OAAO,GAAG,KAAK,CAAC,IAAMC;QAC1D,2GAA2G;QAC3G,MAAMC,UAAU,OAAOC;YACrB,MAAMC,cAAcC,QAAQ,aAAa;YAEzC,MAAMC,mBAAmBhD,UAAU,CAAC;gBAClC,MAAMiD,WAAW,OAAOzB,YACrB,IAAI,CAAC;oBACJ,aAAaX,MAAM,WAAW;oBAC9B,gBAAgBA,MAAM,cAAc;gBACtC,GACC,IAAI,CACHb,cAAc,CAAC,IACbA,WAAW,CAAC;wBACV2B,SAAS;4BAAE,MAAM;4BAAgBS;wBAAW;oBAC9C;gBAIN,IAAIa,SAAS,IAAI,KAAK,YAAY;oBAChCtB,SAAS;wBAAE,MAAM;wBAAkBS;oBAAW;oBAC9C,OAAOa,SAAS,OAAO;oBACvBjB,aAAanB,OAAOoB;oBACpB,OAAO;wBAAE,MAAM;oBAAU;gBAC3B;gBAEA,MAAMiB,sBAAsBxC,qBAAqBA,CAACuB,aAAagB,SAAS,WAAW;gBACnF,IAAIC,oBAAoB,MAAM,KAAKjB,YAAY,MAAM,EAAE;oBACrDN,SAAS;wBAAE,MAAM;wBAAkBS;oBAAW;oBAC9C,OAAOa,SAAS,OAAO;oBACvBjB,aAAanB,OAAOqC;oBACpB,OAAO;wBAAE,MAAM;oBAAU;gBAC3B;gBAEA,IACEjB,YAAY,IAAI,KAAKiB,oBAAoB,IAAI,IAC5CL,CAAAA,wBAAwBF,aAAa9B,MAAM,cAAc,KAAK,UAAS,GACxE;oBACAc,SAAS;wBAAE,MAAM;wBAAkBS;oBAAW;oBAC9C,OAAOa,SAAS,OAAO;oBACvB1B,cAAc,eAAe,CAAC2B,oBAAoB,IAAI;oBACtD,OAAO;wBAAE,MAAM;oBAAU;gBAC3B;gBAEA,MAAMtB,aAAaD,SAAS;oBAAE,MAAM;oBAAeS;oBAAYa;gBAAS;gBACxE,MAAMnB,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,MAAMqB,qBAAqB,OAAOnD,WAAW,CAAC;wBAC5C,IAAIoD;wBACJhD,eAAeA,CAAC;4BACd,MAAMU,YACJS,cAAc,aAAa,IAAI,KAAK,SACpCA,cAAc,eAAe,IAAI,SACjC;4BACF,KAAK,MAAM8B,QAAQzC,4BAA4BA,CAACC,OAAOC,WAAY;gCACjEX,iBAAiBA,CAACkD;4BACpB;4BACAD,aAAa9B,gBAAgB,QAAQ,CAACQ,QAAQ,QAAQ,CAAC,SAAS;wBAClE;wBACA,OAAOsB;oBACT;oBACA,MAAME,YAAY3B,SAAS;wBACzB,MAAM;wBACN,YAAYG,QAAQ,UAAU;wBAC9BqB;wBACA,UAAUrB,QAAQ,QAAQ;oBAC5B;oBACA,IAAIwB,UAAU,OAAO,KAAK,MAAM;wBAC9B,OAAOzB,qBAAqByB,UAAU,OAAO;wBAC7C,OAAO;4BAAE,MAAM;wBAAU;oBAC3B;oBACA,OAAO;wBACL,MAAM;wBACNH;wBACAD;wBACA,UAAUpB,QAAQ,QAAQ;oBAC5B;gBACF;gBAEA,MAAM,IAAIX,UAAU;YACtB;YAEA,gHAAgH;YAChHf,eAAeA,CAAC;gBACd,MAAMqB,IAAIuB,kBAAkB;oBAAE,QAAQR;gBAAiB,GACpD,IAAI,CAACM,YAAY,OAAO,EACxB,KAAK,CAACA,YAAY,MAAM;YAC7B;YAEA,MAAMS,kBAAkBvD,cAAc,CAAC;gBACrC,MAAM4B,aAAaD,SAAS;oBAAE,MAAM;oBAAqBS;gBAAW;gBACpE,OAAOP,qBAAqBD,WAAW,OAAO;YAChD;YACA,MAAM4B,UAAU,MAAMV,YAAY,OAAO,CAAC,KAAK,CAAC,CAACW;gBAC/C,IAAIjB,iBAAiB,OAAO,EAAE;oBAC5B,OAAOf,IAAI8B,gBAAgB,IAAI,CAACvD,SAAS,CAAC;wBAAE,MAAM;oBAAU;gBAC9D;gBACA,IAAI,CAACa,MAAM,UAAU,IAAIA,MAAM,cAAc,KAAK,YAAY;oBAC5DU,cAAc,cAAc;oBAC5B,OAAO;wBAAE,MAAM;oBAAU;gBAC3B;gBACA,MAAMkC;YACR;YACA,IAAID,QAAQ,IAAI,KAAK,WAAW;gBAC9B;YACF;YAEA,MAAM,EAAEL,kBAAkB,EAAED,mBAAmB,EAAED,QAAQ,EAAE,GAAGO;YAC9D,MAAME,0BAA0B1D,0BAA0B,CAAC,CAAC2D,UAC1DA,QAAQ3D,cAAc,CAAC,IAAMmD,mBAAmB,SAAS,GAAG,IAAI,CAC9DnD,UAAU,CACRA,cAAc,CAAC;oBACb,MAAM4B,aAAaD,SAAS;wBAC1B,MAAM;wBACNS;oBACF;oBACA,OAAOP,qBAAqBD,WAAW,OAAO;gBAChD,KAEF5B,aAAa,CAAC,CAAC4D,OAAU3D,cAAc,CAAC2D,QAAQL,kBAAkBvD,cAAW;YAGjF,IAAI;gBACF,MAAMyB,IAAIiC,yBAAyB;oBAAE,QAAQlB;gBAAiB;YAChE,EAAE,OAAOiB,OAAO;gBACd,IAAIjB,iBAAiB,OAAO,EAAE;oBAC5B;gBACF;gBACA,MAAMiB;YACR;YAEA,MAAMI,0BAA0B7D,UAAU,CAAC;gBACzC,OAAOA,cAAc,CAAC,IAAMmD,mBAAmB,OAAO;gBACtD,MAAMvB,aAAaD,SAAS;oBAAE,MAAM;oBAAiBS;gBAAW;gBAChE,OAAOP,qBAAqBD,WAAW,OAAO;YAChD,GAAG,IAAI,CAAC5B,aAAa;YACrB,KAAKyB,IAAIoC,yBAAyB,KAAK,CAAC,IAAMlB;YAE9C,MAAMmB,0BAA0B9D,UAAU,CAAC;gBACzC,MAAM+D,aAAa,OAAO/D,WAAW,CAACiD,SAAS,SAAS;gBACxD,MAAMrB,aAAaD,SAAS;oBAC1B,MAAM1B,cAAc,CAAC8D,cAAc,oBAAoB;oBACvD3B;gBACF;gBACA,OAAOP,qBAAqBD,WAAW,OAAO;YAChD;YACA,KAAKH,IAAIqC,yBAAyB,KAAK,CAAC,IAAMnB;YAE9C,IAAIV,YAAY,IAAI,KAAKiB,oBAAoB,IAAI,IAAIL,wBAAwBF,WAAW;gBACtFE,oBAAoB,QAAQ,CAACK,oBAAoB,IAAI,EAAE;oBAAE,SAAS;gBAAO;YAC3E;YACA,MAAMc,gBAAgBhE,cAAc,CAAC;gBACnC,MAAM4B,aAAaD,SAAS;oBAC1B,MAAM;oBACN,OAAOJ,cAAc,eAAe;oBACpCa;gBACF;gBACA,OAAOP,qBAAqBD,WAAW,OAAO;YAChD;YACA,IAAIiB,wBAAwBF,WAAW;gBACrC,MAAMlB,IAAIuC;YACZ,OAAO;gBACLnB,oBAAoB,UAAU,CAAC,IAAMpB,IAAIuC;YAC3C;QACF;QAEAnD,MAAM,SAAS,CACbA,MAAM,UAAU,GACZ;YAAE,kBAAkB+B;QAAQ,IAC5B;YACE,oFAAoF;YACpFA;QACF;IAER;IAEA,OAAO5C,qBAAqB,CAC1BA,WAAW,CAAC,IAAMuB,cAAc,SAAS,CAACW,cAC1C,CAAC+B,cAAgBjE,WAAW,CAACiE;AAEjC,GAAG"}
|
|
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":"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"}
|
|
@@ -88,15 +88,14 @@ class FlightClient extends Context.Service()('ersc/client/FlightClient', {
|
|
|
88
88
|
reason: 'UnexpectedResponse'
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
|
-
|
|
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
|
|
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(
|
|
98
|
+
try: ()=>new URL(response.url),
|
|
100
99
|
catch: (cause)=>new FlightLoadError({
|
|
101
100
|
cause,
|
|
102
101
|
reason: 'UnexpectedResponse'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client/flight-client.js","sources":["../../src/client/flight-client.ts"],"sourcesContent":["// oxlint-disable effecttsgo/process-env-in-effect -- Rspack replaces NODE_ENV at compile time.\nimport { Context, Deferred, Effect, Exit, Layer, Schema, Scope, Stream } from 'effect';\nimport { HttpBody, HttpClient, HttpClientRequest } from 'effect/unstable/http';\nimport {\n createFromReadableStream,\n type TemporaryReferenceSet,\n} from 'react-server-dom-rspack/client.browser';\n\nimport { FlightMediaType, ServerFnIdHeader, type FlightPayload } from '../rsc/flight';\nimport { InitialFlightStream } from './initial-flight-stream';\n\nexport class FlightLoadError extends Schema.TaggedError<FlightLoadError>()('FlightLoadError', {\n cause: Schema.Defect(),\n reason: Schema.Literals(['RequestFailed', 'UnexpectedResponse', 'DecodeFailed']),\n}) {}\n\nexport type FlightRequest =\n | {\n readonly _tag: 'Navigation';\n readonly destination: URL;\n }\n | {\n readonly _tag: 'ServerFunction';\n readonly body: BodyInit;\n readonly destination: URL;\n readonly id: string;\n readonly temporaryReferences: TemporaryReferenceSet;\n };\n\ntype DecodedFlight = {\n readonly completed: Effect.Effect<void, FlightLoadError>;\n readonly payload: FlightPayload;\n};\n\ntype FlightResource = DecodedFlight & {\n readonly _tag: 'Flight';\n readonly release: Effect.Effect<void>;\n readonly resolvedUrl: URL;\n};\n\ntype DocumentResource = {\n readonly _tag: 'Document';\n readonly release: Effect.Effect<void>;\n};\n\nexport class FlightClient extends Context.Service<FlightClient>()('ersc/client/FlightClient', {\n make: Effect.gen(function* () {\n const httpClient = yield* HttpClient.HttpClient;\n const initialFlight = yield* InitialFlightStream;\n\n const loadInitial = Effect.gen(function* () {\n const completed = Promise.withResolvers<void>();\n const stream = initialFlight.stream.pipeThrough(\n new TransformStream({\n flush: () => completed.resolve(),\n transform: (chunk, controller) => controller.enqueue(chunk),\n }),\n );\n const payload = yield* Effect.tryPromise({\n try: () =>\n createFromReadableStream<FlightPayload>(\n stream,\n process.env.NODE_ENV === 'development' ? { startTime: 0 } : undefined,\n ),\n catch: (cause) => new FlightLoadError({ cause, reason: 'DecodeFailed' }),\n });\n\n return {\n completed: Effect.promise(() => completed.promise),\n payload,\n } satisfies DecodedFlight;\n });\n\n const load = Effect.fnUntraced(function* (flightRequest: FlightRequest) {\n const parentScope = yield* Effect.scope;\n const responseScope = yield* Scope.fork(parentScope);\n const release = Scope.close(responseScope, Exit.void);\n\n return yield* Effect.gen(function* () {\n const client = httpClient.pipe(HttpClient.withScope);\n const request =\n flightRequest._tag === 'Navigation'\n ? HttpClientRequest.get(flightRequest.destination).pipe(\n HttpClientRequest.setHeader('accept', FlightMediaType),\n )\n : HttpClientRequest.post(flightRequest.destination).pipe(\n HttpClientRequest.setHeaders({\n accept: FlightMediaType,\n [ServerFnIdHeader]: flightRequest.id,\n }),\n HttpClientRequest.setBody(HttpBody.raw(flightRequest.body)),\n );\n const requestStartTime = process.env.NODE_ENV === 'development' ? performance.now() : 0;\n const response = yield* client.execute(request).pipe(\n Scope.provide(responseScope),\n Effect.mapError(\n (cause) =>\n new FlightLoadError({\n cause,\n reason: 'RequestFailed',\n }),\n ),\n );\n if (response.status < 200 || response.status >= 300) {\n if (flightRequest._tag === 'Navigation') {\n return { _tag: 'Document', release } satisfies DocumentResource;\n }\n return yield* new FlightLoadError({\n cause: new Error(`Flight request failed with status ${response.status}.`),\n reason: 'RequestFailed',\n });\n }\n const contentType = response.headers['content-type']\n ?.split(';', 1)[0]\n ?.trim()\n .toLowerCase();\n if (contentType !== FlightMediaType) {\n if (flightRequest._tag === 'Navigation') {\n return { _tag: 'Document', release } satisfies DocumentResource;\n }\n return yield* new FlightLoadError({\n cause: new Error(\n `Expected a ${FlightMediaType} response, received ${response.headers['content-type'] ?? 'no content type'}.`,\n ),\n reason: 'UnexpectedResponse',\n });\n }\n\n const contentLocation = response.headers['content-location'];\n if (contentLocation === undefined) {\n return yield* new FlightLoadError({\n cause: new Error('Expected the Flight response to include a Content-Location header.'),\n reason: 'UnexpectedResponse',\n });\n }\n const resolvedUrl = yield* Effect.try({\n try: () => new URL(contentLocation, flightRequest.destination),\n catch: (cause) =>\n new FlightLoadError({\n cause,\n reason: 'UnexpectedResponse',\n }),\n });\n\n const completed = yield* Deferred.make<void, FlightLoadError>();\n const responseBody = yield* Stream.toReadableStreamEffect(\n response.stream.pipe(\n Stream.onExit((exit) =>\n Deferred.done(\n completed,\n exit.pipe(\n Exit.mapError(\n (cause) =>\n new FlightLoadError({\n cause,\n reason: 'RequestFailed',\n }),\n ),\n Exit.asVoid,\n ),\n ),\n ),\n Stream.ensuring(release),\n ),\n );\n const decodeOptions =\n flightRequest._tag === 'ServerFunction'\n ? process.env.NODE_ENV === 'development'\n ? {\n startTime: requestStartTime,\n temporaryReferences: flightRequest.temporaryReferences,\n }\n : { temporaryReferences: flightRequest.temporaryReferences }\n : process.env.NODE_ENV === 'development'\n ? {\n startTime: requestStartTime,\n }\n : undefined;\n const payload = yield* Effect.tryPromise({\n try: () => createFromReadableStream<FlightPayload>(responseBody, decodeOptions),\n catch: (cause) =>\n new FlightLoadError({\n cause,\n reason: 'DecodeFailed',\n }),\n });\n\n return {\n _tag: 'Flight',\n completed: Deferred.await(completed),\n payload,\n release,\n resolvedUrl,\n } satisfies FlightResource;\n }).pipe(Effect.onError(() => release));\n });\n\n return { load, loadInitial };\n }),\n}) {\n static readonly layer = Layer.effect(this, this.make);\n\n static readonly layerTest = Layer.mock(this);\n}\n"],"names":["Context","Deferred","Effect","Exit","Layer","Schema","Scope","Stream","HttpBody","HttpClient","HttpClientRequest","createFromReadableStream","FlightMediaType","ServerFnIdHeader","InitialFlightStream","FlightLoadError","FlightClient","httpClient","initialFlight","loadInitial","completed","Promise","stream","TransformStream","chunk","controller","payload","process","undefined","cause","load","flightRequest","parentScope","responseScope","release","client","request","requestStartTime","performance","response","Error","contentType","contentLocation","resolvedUrl","URL","responseBody","exit","decodeOptions"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client/flight-client.js","sources":["../../src/client/flight-client.ts"],"sourcesContent":["// oxlint-disable effecttsgo/process-env-in-effect -- Rspack replaces NODE_ENV at compile time.\nimport { Context, Deferred, Effect, Exit, Layer, Schema, Scope, Stream } from 'effect';\nimport { HttpBody, HttpClient, HttpClientRequest } from 'effect/unstable/http';\nimport {\n createFromReadableStream,\n type TemporaryReferenceSet,\n} from 'react-server-dom-rspack/client.browser';\n\nimport { FlightMediaType, ServerFnIdHeader, type FlightPayload } from '../rsc/flight';\nimport { InitialFlightStream } from './initial-flight-stream';\n\nexport class FlightLoadError extends Schema.TaggedError<FlightLoadError>()('FlightLoadError', {\n cause: Schema.Defect(),\n reason: Schema.Literals(['RequestFailed', 'UnexpectedResponse', 'DecodeFailed']),\n}) {}\n\nexport type FlightRequest =\n | {\n readonly _tag: 'Navigation';\n readonly destination: URL;\n }\n | {\n readonly _tag: 'ServerFunction';\n readonly body: BodyInit;\n readonly destination: URL;\n readonly id: string;\n readonly temporaryReferences: TemporaryReferenceSet;\n };\n\ntype DecodedFlight = {\n readonly completed: Effect.Effect<void, FlightLoadError>;\n readonly payload: FlightPayload;\n};\n\ntype FlightResource = DecodedFlight & {\n readonly _tag: 'Flight';\n readonly release: Effect.Effect<void>;\n readonly resolvedUrl: URL;\n};\n\ntype DocumentResource = {\n readonly _tag: 'Document';\n readonly release: Effect.Effect<void>;\n};\n\nexport class FlightClient extends Context.Service<FlightClient>()('ersc/client/FlightClient', {\n make: Effect.gen(function* () {\n const httpClient = yield* HttpClient.HttpClient;\n const initialFlight = yield* InitialFlightStream;\n\n const loadInitial = Effect.gen(function* () {\n const completed = Promise.withResolvers<void>();\n const stream = initialFlight.stream.pipeThrough(\n new TransformStream({\n flush: () => completed.resolve(),\n transform: (chunk, controller) => controller.enqueue(chunk),\n }),\n );\n const payload = yield* Effect.tryPromise({\n try: () =>\n createFromReadableStream<FlightPayload>(\n stream,\n process.env.NODE_ENV === 'development' ? { startTime: 0 } : undefined,\n ),\n catch: (cause) => new FlightLoadError({ cause, reason: 'DecodeFailed' }),\n });\n\n return {\n completed: Effect.promise(() => completed.promise),\n payload,\n } satisfies DecodedFlight;\n });\n\n const load = Effect.fnUntraced(function* (flightRequest: FlightRequest) {\n const parentScope = yield* Effect.scope;\n const responseScope = yield* Scope.fork(parentScope);\n const release = Scope.close(responseScope, Exit.void);\n\n return yield* Effect.gen(function* () {\n const client = httpClient.pipe(HttpClient.withScope);\n const request =\n flightRequest._tag === 'Navigation'\n ? HttpClientRequest.get(flightRequest.destination).pipe(\n HttpClientRequest.setHeader('accept', FlightMediaType),\n )\n : HttpClientRequest.post(flightRequest.destination).pipe(\n HttpClientRequest.setHeaders({\n accept: FlightMediaType,\n [ServerFnIdHeader]: flightRequest.id,\n }),\n HttpClientRequest.setBody(HttpBody.raw(flightRequest.body)),\n );\n const requestStartTime = process.env.NODE_ENV === 'development' ? performance.now() : 0;\n const response = yield* client.execute(request).pipe(\n Scope.provide(responseScope),\n Effect.mapError(\n (cause) =>\n new FlightLoadError({\n cause,\n reason: 'RequestFailed',\n }),\n ),\n );\n if (response.status < 200 || response.status >= 300) {\n if (flightRequest._tag === 'Navigation') {\n return { _tag: 'Document', release } satisfies DocumentResource;\n }\n return yield* new FlightLoadError({\n cause: new Error(`Flight request failed with status ${response.status}.`),\n reason: 'RequestFailed',\n });\n }\n const contentType = response.headers['content-type']\n ?.split(';', 1)[0]\n ?.trim()\n .toLowerCase();\n if (contentType !== FlightMediaType) {\n if (flightRequest._tag === 'Navigation') {\n return { _tag: 'Document', release } satisfies DocumentResource;\n }\n return yield* new FlightLoadError({\n cause: new Error(\n `Expected a ${FlightMediaType} response, received ${response.headers['content-type'] ?? 'no content type'}.`,\n ),\n reason: 'UnexpectedResponse',\n });\n }\n\n if (response.url === '') {\n return yield* new FlightLoadError({\n cause: new Error('Expected the Flight response to include a resolved URL.'),\n reason: 'UnexpectedResponse',\n });\n }\n const resolvedUrl = yield* Effect.try({\n try: () => new URL(response.url),\n catch: (cause) =>\n new FlightLoadError({\n cause,\n reason: 'UnexpectedResponse',\n }),\n });\n\n const completed = yield* Deferred.make<void, FlightLoadError>();\n const responseBody = yield* Stream.toReadableStreamEffect(\n response.stream.pipe(\n Stream.onExit((exit) =>\n Deferred.done(\n completed,\n exit.pipe(\n Exit.mapError(\n (cause) =>\n new FlightLoadError({\n cause,\n reason: 'RequestFailed',\n }),\n ),\n Exit.asVoid,\n ),\n ),\n ),\n Stream.ensuring(release),\n ),\n );\n const decodeOptions =\n flightRequest._tag === 'ServerFunction'\n ? process.env.NODE_ENV === 'development'\n ? {\n startTime: requestStartTime,\n temporaryReferences: flightRequest.temporaryReferences,\n }\n : { temporaryReferences: flightRequest.temporaryReferences }\n : process.env.NODE_ENV === 'development'\n ? {\n startTime: requestStartTime,\n }\n : undefined;\n const payload = yield* Effect.tryPromise({\n try: () => createFromReadableStream<FlightPayload>(responseBody, decodeOptions),\n catch: (cause) =>\n new FlightLoadError({\n cause,\n reason: 'DecodeFailed',\n }),\n });\n\n return {\n _tag: 'Flight',\n completed: Deferred.await(completed),\n payload,\n release,\n resolvedUrl,\n } satisfies FlightResource;\n }).pipe(Effect.onError(() => release));\n });\n\n return { load, loadInitial };\n }),\n}) {\n static readonly layer = Layer.effect(this, this.make);\n\n static readonly layerTest = Layer.mock(this);\n}\n"],"names":["Context","Deferred","Effect","Exit","Layer","Schema","Scope","Stream","HttpBody","HttpClient","HttpClientRequest","createFromReadableStream","FlightMediaType","ServerFnIdHeader","InitialFlightStream","FlightLoadError","FlightClient","httpClient","initialFlight","loadInitial","completed","Promise","stream","TransformStream","chunk","controller","payload","process","undefined","cause","load","flightRequest","parentScope","responseScope","release","client","request","requestStartTime","performance","response","Error","contentType","resolvedUrl","URL","responseBody","exit","decodeOptions"],"mappings":"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"}
|
|
@@ -108,12 +108,13 @@ class ReactDOMRenderer extends Context.Service()('ersc/client/ReactDOMRenderer',
|
|
|
108
108
|
}, [
|
|
109
109
|
render
|
|
110
110
|
]);
|
|
111
|
+
const routeTree = render._tag === 'Discard' ? render.restore.routeTree : render.routeTree;
|
|
111
112
|
return /*#__PURE__*/ jsx(BrowserErrorBoundary, {
|
|
112
113
|
onError: reportError,
|
|
113
114
|
onRendered: reportRendered,
|
|
114
115
|
render: render,
|
|
115
116
|
children: /*#__PURE__*/ jsx(RouteTree, {
|
|
116
|
-
root:
|
|
117
|
+
root: routeTree
|
|
117
118
|
})
|
|
118
119
|
});
|
|
119
120
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client/react-dom-renderer.js","sources":["../../src/client/react-dom-renderer.tsx"],"sourcesContent":["import { Context, Effect, Layer, Schema } from 'effect';\nimport {\n Component,\n type ErrorInfo,\n type ReactNode,\n StrictMode,\n useLayoutEffect,\n useState,\n} from 'react';\nimport { hydrateRoot } from 'react-dom/client';\n\nimport type { FlightPayload } from '../rsc/flight';\nimport { BrowserEffectRunner } from './browser-effect-runner';\nimport { BrowserRenderStatus } from './browser-render-status';\nimport { type BrowserRender, BrowserRenderer } from './browser-renderer';\nimport { BrowserFailureScreen } from './browser-screen';\nimport { RouteTree } from './route-tree';\n\nexport class ReactDOMHydrationError extends Schema.TaggedError<ReactDOMHydrationError>()(\n 'ReactDOMHydrationError',\n { cause: Schema.Defect() },\n) {}\n\ntype BrowserErrorBoundaryState =\n | { readonly _tag: 'Uninitialized' }\n | { readonly _tag: 'Ready'; readonly render: BrowserRender }\n | { readonly _tag: 'Failed'; readonly render: BrowserRender };\ntype BrowserErrorBoundaryProps = {\n readonly children: ReactNode;\n readonly onError: (error: unknown, info: ErrorInfo) => void;\n readonly onRendered: () => void;\n readonly render: BrowserRender;\n};\n\nclass BrowserErrorBoundary extends Component<BrowserErrorBoundaryProps, BrowserErrorBoundaryState> {\n override readonly state: BrowserErrorBoundaryState = { _tag: 'Uninitialized' };\n\n static getDerivedStateFromError() {\n return { _tag: 'Failed' } as const;\n }\n\n static getDerivedStateFromProps(\n props: BrowserErrorBoundaryProps,\n state: BrowserErrorBoundaryState,\n ): BrowserErrorBoundaryState | null {\n if (state._tag !== 'Uninitialized' && props.render === state.render) {\n return null;\n }\n // Discard acknowledges a cancelled candidate, not a request to retry the failed tree.\n return state._tag === 'Failed' && props.render._tag === 'Discard'\n ? { _tag: 'Failed', render: props.render }\n : { _tag: 'Ready', render: props.render };\n }\n\n override componentDidCatch(error: unknown, info: ErrorInfo) {\n this.props.onError(error, info);\n }\n\n override componentDidMount() {\n if (this.state._tag === 'Ready') {\n this.props.onRendered();\n }\n }\n\n override componentDidUpdate() {\n if (this.state._tag === 'Ready') {\n this.props.onRendered();\n }\n }\n\n override render() {\n if (this.state._tag === 'Failed') {\n return <BrowserFailureScreen />;\n }\n\n return this.props.children;\n }\n}\n\nexport class ReactDOMRenderer extends Context.Service<ReactDOMRenderer>()(\n 'ersc/client/ReactDOMRenderer',\n {\n make: Effect.gen(function* () {\n const browserRenderer = yield* BrowserRenderer;\n const run = yield* BrowserEffectRunner;\n const renderStatus = yield* BrowserRenderStatus;\n\n const hydrate = Effect.fnUntraced(function* (\n container: Element | Document,\n initialPayload: FlightPayload,\n ) {\n const browserRendererReady = Promise.withResolvers<void>();\n const reportError = (error: unknown, info: ErrorInfo) => {\n void run(\n Effect.gen(function* () {\n yield* renderStatus.report({\n _tag: 'Failed',\n error,\n componentStack: info.componentStack ?? null,\n });\n yield* Effect.logError('Uncaught client render error.', error, info.componentStack);\n }),\n );\n };\n\n const reportRendered = () => {\n void run(renderStatus.report({ _tag: 'Rendered' }));\n };\n\n function Root() {\n const [render, setRender] = useState<BrowserRender>(() => ({\n _tag: 'Initial',\n routeTree: initialPayload.routeTree,\n }));\n\n useLayoutEffect(() => {\n browserRenderer.initialize(initialPayload.routeTree, setRender);\n browserRendererReady.resolve();\n }, []);\n\n useLayoutEffect(() => {\n browserRenderer.commit(render);\n }, [render]);\n\n return (\n <BrowserErrorBoundary onError={reportError} onRendered={reportRendered} render={render}>\n <RouteTree root={
|
|
1
|
+
{"version":3,"file":"client/react-dom-renderer.js","sources":["../../src/client/react-dom-renderer.tsx"],"sourcesContent":["import { Context, Effect, Layer, Schema } from 'effect';\nimport {\n Component,\n type ErrorInfo,\n type ReactNode,\n StrictMode,\n useLayoutEffect,\n useState,\n} from 'react';\nimport { hydrateRoot } from 'react-dom/client';\n\nimport type { FlightPayload } from '../rsc/flight';\nimport { BrowserEffectRunner } from './browser-effect-runner';\nimport { BrowserRenderStatus } from './browser-render-status';\nimport { type BrowserRender, BrowserRenderer } from './browser-renderer';\nimport { BrowserFailureScreen } from './browser-screen';\nimport { RouteTree } from './route-tree';\n\nexport class ReactDOMHydrationError extends Schema.TaggedError<ReactDOMHydrationError>()(\n 'ReactDOMHydrationError',\n { cause: Schema.Defect() },\n) {}\n\ntype BrowserErrorBoundaryState =\n | { readonly _tag: 'Uninitialized' }\n | { readonly _tag: 'Ready'; readonly render: BrowserRender }\n | { readonly _tag: 'Failed'; readonly render: BrowserRender };\ntype BrowserErrorBoundaryProps = {\n readonly children: ReactNode;\n readonly onError: (error: unknown, info: ErrorInfo) => void;\n readonly onRendered: () => void;\n readonly render: BrowserRender;\n};\n\nclass BrowserErrorBoundary extends Component<BrowserErrorBoundaryProps, BrowserErrorBoundaryState> {\n override readonly state: BrowserErrorBoundaryState = { _tag: 'Uninitialized' };\n\n static getDerivedStateFromError() {\n return { _tag: 'Failed' } as const;\n }\n\n static getDerivedStateFromProps(\n props: BrowserErrorBoundaryProps,\n state: BrowserErrorBoundaryState,\n ): BrowserErrorBoundaryState | null {\n if (state._tag !== 'Uninitialized' && props.render === state.render) {\n return null;\n }\n // Discard acknowledges a cancelled candidate, not a request to retry the failed tree.\n return state._tag === 'Failed' && props.render._tag === 'Discard'\n ? { _tag: 'Failed', render: props.render }\n : { _tag: 'Ready', render: props.render };\n }\n\n override componentDidCatch(error: unknown, info: ErrorInfo) {\n this.props.onError(error, info);\n }\n\n override componentDidMount() {\n if (this.state._tag === 'Ready') {\n this.props.onRendered();\n }\n }\n\n override componentDidUpdate() {\n if (this.state._tag === 'Ready') {\n this.props.onRendered();\n }\n }\n\n override render() {\n if (this.state._tag === 'Failed') {\n return <BrowserFailureScreen />;\n }\n\n return this.props.children;\n }\n}\n\nexport class ReactDOMRenderer extends Context.Service<ReactDOMRenderer>()(\n 'ersc/client/ReactDOMRenderer',\n {\n make: Effect.gen(function* () {\n const browserRenderer = yield* BrowserRenderer;\n const run = yield* BrowserEffectRunner;\n const renderStatus = yield* BrowserRenderStatus;\n\n const hydrate = Effect.fnUntraced(function* (\n container: Element | Document,\n initialPayload: FlightPayload,\n ) {\n const browserRendererReady = Promise.withResolvers<void>();\n const reportError = (error: unknown, info: ErrorInfo) => {\n void run(\n Effect.gen(function* () {\n yield* renderStatus.report({\n _tag: 'Failed',\n error,\n componentStack: info.componentStack ?? null,\n });\n yield* Effect.logError('Uncaught client render error.', error, info.componentStack);\n }),\n );\n };\n\n const reportRendered = () => {\n void run(renderStatus.report({ _tag: 'Rendered' }));\n };\n\n function Root() {\n const [render, setRender] = useState<BrowserRender>(() => ({\n _tag: 'Initial',\n routeTree: initialPayload.routeTree,\n }));\n\n useLayoutEffect(() => {\n browserRenderer.initialize(initialPayload.routeTree, setRender);\n browserRendererReady.resolve();\n }, []);\n\n useLayoutEffect(() => {\n browserRenderer.commit(render);\n }, [render]);\n\n const routeTree = render._tag === 'Discard' ? render.restore.routeTree : render.routeTree;\n return (\n <BrowserErrorBoundary onError={reportError} onRendered={reportRendered} render={render}>\n <RouteTree root={routeTree} />\n </BrowserErrorBoundary>\n );\n }\n\n yield* Effect.acquireRelease(\n Effect.try({\n try: () =>\n hydrateRoot(\n container,\n <StrictMode>\n <Root />\n </StrictMode>,\n { formState: initialPayload.formState },\n ),\n catch: (cause) => new ReactDOMHydrationError({ cause }),\n }),\n (root) => Effect.sync(() => root.unmount()),\n );\n yield* Effect.promise(() => browserRendererReady.promise);\n });\n\n return { hydrate };\n }),\n },\n) {\n static readonly layer = Layer.effect(this, this.make);\n}\n"],"names":["Context","Effect","Layer","Schema","Component","StrictMode","useLayoutEffect","useState","hydrateRoot","BrowserEffectRunner","BrowserRenderStatus","BrowserRenderer","BrowserFailureScreen","RouteTree","ReactDOMHydrationError","BrowserErrorBoundary","props","state","error","info","ReactDOMRenderer","browserRenderer","run","renderStatus","hydrate","container","initialPayload","browserRendererReady","Promise","reportError","reportRendered","Root","render","setRender","routeTree","cause","root"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Context, Effect, Layer } from 'effect';
|
|
1
|
+
import { Context, Effect, Layer, Scope } from 'effect';
|
|
2
2
|
import { BrowserRenderer } from './browser-renderer.js';
|
|
3
3
|
import { NavigationApi } from './navigation-api.js';
|
|
4
4
|
import { RouteLoader } from './route-loader.js';
|
|
@@ -26,5 +26,5 @@ export declare class RouteRefresher extends RouteRefresher_base {
|
|
|
26
26
|
replace?: (replacement: RouteRefreshImplementation) => Effect.Effect<void, never, never>;
|
|
27
27
|
}) => Layer.Layer<RouteRefresher, never, never>;
|
|
28
28
|
}
|
|
29
|
-
export declare const installRouteRefresh: Effect.Effect<void, never, BrowserRenderer | NavigationApi | RouteLoader | RouteRefresher |
|
|
29
|
+
export declare const installRouteRefresh: Effect.Effect<void, never, BrowserRenderer | NavigationApi | RouteLoader | RouteRefresher | Scope.Scope>;
|
|
30
30
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Context, Effect,
|
|
1
|
+
import { Context, Effect, Exit, FiberHandle, Layer, Ref, Scope } from "effect";
|
|
2
2
|
import { addTransitionType, startTransition } from "react";
|
|
3
3
|
import { BrowserRenderer } from "./browser-renderer.js";
|
|
4
4
|
import { NavigationApi } from "./navigation-api.js";
|
|
@@ -17,7 +17,6 @@ import { RouteLoader } from "./route-loader.js";
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
const CurrentRouteRefreshKey = 'CurrentRouteRefresh';
|
|
21
20
|
class RouteRefresher extends Context.Service()('ersc/client/RouteRefresher', {
|
|
22
21
|
make: Effect.gen(function*() {
|
|
23
22
|
const navigationApi = yield* NavigationApi;
|
|
@@ -48,7 +47,8 @@ const installRouteRefresh = Effect.gen(function*() {
|
|
|
48
47
|
const navigationApi = yield* NavigationApi;
|
|
49
48
|
const routeLoader = yield* RouteLoader;
|
|
50
49
|
const routeRefresher = yield* RouteRefresher;
|
|
51
|
-
const refreshes = yield*
|
|
50
|
+
const refreshes = yield* FiberHandle.make();
|
|
51
|
+
const browserScope = yield* Effect.scope;
|
|
52
52
|
const waitForNavigationIdle = Effect.suspend(()=>{
|
|
53
53
|
const transition = navigationApi.getTransition();
|
|
54
54
|
return transition === null ? Effect.succeed('Idle') : Effect.promise(()=>transition.finished.then(()=>undefined, ()=>undefined)).pipe(Effect.as('Settled'));
|
|
@@ -65,41 +65,56 @@ const installRouteRefresh = Effect.gen(function*() {
|
|
|
65
65
|
return Effect.sync(unsubscribe);
|
|
66
66
|
});
|
|
67
67
|
const refreshRoute = Effect.fnUntraced(function*(transitionType) {
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
destination
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
68
|
+
const responseScope = yield* Scope.make();
|
|
69
|
+
const render = yield* Effect.uninterruptibleMask(Effect.fnUntraced(function*(restore) {
|
|
70
|
+
const currentEntry = navigationApi.getCurrentEntry();
|
|
71
|
+
const destination = new URL(currentEntry?.url ?? navigationApi.getCurrentUrl());
|
|
72
|
+
const resource = yield* restore(routeLoader.load({
|
|
73
|
+
destination: {
|
|
74
|
+
id: currentEntry?.id ?? '',
|
|
75
|
+
url: destination.href
|
|
76
|
+
},
|
|
77
|
+
navigationType: 'replace'
|
|
78
|
+
}).pipe(Scope.provide(responseScope)));
|
|
79
|
+
const release = resource.release.pipe(Scope.use(responseScope));
|
|
80
|
+
if (resource._tag === 'Document') {
|
|
81
|
+
yield* release;
|
|
82
|
+
yield* Effect.sync(navigationApi.reloadDocument);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const resolvedDestination = preserveRequestedHash(destination, resource.resolvedUrl);
|
|
86
|
+
if (resolvedDestination.href !== destination.href) {
|
|
87
|
+
yield* release;
|
|
88
|
+
yield* Effect.sync(()=>navigationApi.replaceDocument(resolvedDestination.href));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const commitRefresh = routeLoader.prepareRefresh(resource.routeTree);
|
|
92
|
+
let published;
|
|
93
|
+
yield* Effect.sync(()=>{
|
|
94
|
+
startTransition(()=>{
|
|
95
|
+
addTransitionType(transitionType);
|
|
96
|
+
published = browserRenderer.refresh(resource.routeTree);
|
|
97
|
+
});
|
|
94
98
|
});
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
// Finish publication and install its browser-owned lifetime before allowing cancellation.
|
|
100
|
+
yield* Effect.raceFirst(Effect.all([
|
|
101
|
+
Effect.promise(()=>published.committed),
|
|
102
|
+
resource.completed
|
|
103
|
+
], {
|
|
104
|
+
concurrency: 'unbounded',
|
|
105
|
+
discard: true
|
|
106
|
+
}).pipe(Effect.andThen(Effect.sync(commitRefresh))), Effect.promise(()=>published.retired)).pipe(Effect.ensuring(release), Effect["catch"]((cause)=>Effect.logError('Failed to stream the refreshed route.', cause)), Effect.forkIn(browserScope, {
|
|
107
|
+
startImmediately: true
|
|
108
|
+
}));
|
|
109
|
+
yield* Effect.addFinalizer(()=>Effect.sync(()=>{
|
|
110
|
+
// The stream fiber awaits retirement; waiting here could block the replacement render.
|
|
111
|
+
void published.discard();
|
|
112
|
+
}));
|
|
113
|
+
return published;
|
|
114
|
+
}, Effect.onError((cause)=>Scope.close(responseScope, Exit.failCause(cause)))));
|
|
115
|
+
if (render !== undefined) {
|
|
116
|
+
yield* Effect.promise(()=>render.committed);
|
|
117
|
+
}
|
|
103
118
|
});
|
|
104
119
|
const refreshCurrentRoute = Effect.fnUntraced(function*(transitionType) {
|
|
105
120
|
routeLoader.invalidate();
|
|
@@ -109,8 +124,8 @@ const installRouteRefresh = Effect.gen(function*() {
|
|
|
109
124
|
yield* Effect.raceFirst(refreshRoute(transitionType), waitForRoutedNavigation);
|
|
110
125
|
}, Effect.scoped, Effect["catch"]((cause)=>Effect.logError('Failed to refresh the current route.', cause)));
|
|
111
126
|
yield* routeRefresher.replace({
|
|
112
|
-
interruptCurrentRouteRefresh:
|
|
113
|
-
refreshCurrentRoute: (transitionType)=>
|
|
127
|
+
interruptCurrentRouteRefresh: FiberHandle.clear(refreshes),
|
|
128
|
+
refreshCurrentRoute: (transitionType)=>FiberHandle.run(refreshes, refreshCurrentRoute(transitionType)).pipe(Effect.asVoid)
|
|
114
129
|
});
|
|
115
130
|
});
|
|
116
131
|
|