| 1 | /** |
| 2 | * `@alchemy.run/frontend-frameworks/react-router` — React Router v7 |
| 3 | * (framework mode) integration implementing framework-core's `Framework` |
| 4 | * service, with the deploy target passed as a value (AWS Lambda by default, |
| 5 | * via the `@alchemy.run/frontend-frameworks/react-router/aws` subpath |
| 6 | * module). |
| 7 | * |
| 8 | * React Router v7 is expressed as a Vite plugin: `reactRouter()` owns |
| 9 | * routing, typegen, resource routes, and the client/server builds. This |
| 10 | * integration drives the project's own Vite install through the same two |
| 11 | * passes `react-router build` runs, makes the server build's input a fetch |
| 12 | * handler over the emitted `ServerBuild` manifest, and forces the server |
| 13 | * bundle to be self-contained so it deploys as a standalone Lambda — the |
| 14 | * project's `vite.config.ts` needs no adapter wiring. |
| 15 | * |
| 16 | * React Server Components (React Router's `unstable` RSC plugin) and |
| 17 | * multi-environment builds are not supported yet. |
| 18 | * |
| 19 | * The default export is the e2e-harness factory contract: a |
| 20 | * `(options) => Layer<Framework>` function. Use {@link layer} directly for |
| 21 | * the fully-typed path with React Router-specific options. |
| 22 | * |
| 23 | * This module (and `ReactRouter.ts`) is target-agnostic by contract: it must |
| 24 | * not import anything AWS-specific. The AWS half — the Lambda entry and the |
| 25 | * streaming adapter — lives behind |
| 26 | * `@alchemy.run/frontend-frameworks/react-router/aws`. |
| 27 | */ |
| 28 | import type * as FileSystem from "effect/FileSystem"; |
| 29 | import type * as Layer from "effect/Layer"; |
| 30 | import type * as Path from "effect/Path"; |
| 31 | import type { Framework } from "../core/index.ts"; |
| 32 | import { layer, type ReactRouterOptions } from "./ReactRouter.ts"; |
| 33 | |
| 34 | export { |
| 35 | captureOutDirPlugin, |
| 36 | DEFAULT_BUILD_DIRECTORY, |
| 37 | DEFAULT_SERVER_BUILD_FILE, |
| 38 | DEFAULT_TARGET_SPECIFIER, |
| 39 | inlineClientBuildConfig, |
| 40 | inlineServerBuildConfig, |
| 41 | layer, |
| 42 | make, |
| 43 | REACT_ROUTER_PLUGIN_SPECIFIER, |
| 44 | REACT_ROUTER_SERVER_BUILD_ID, |
| 45 | readReactRouterOutput, |
| 46 | selectServerEntryName, |
| 47 | SERVER_ENTRY_ID, |
| 48 | serverEntryPlugin, |
| 49 | serverEntrySource, |
| 50 | type InlineVitePlugin, |
| 51 | type OutDirCapture, |
| 52 | type ReactRouterOptions, |
| 53 | type ReactRouterOutputDirs, |
| 54 | type ReactRouterTarget, |
| 55 | type ReactRouterTargetConfig, |
| 56 | type ReactRouterTargetInput, |
| 57 | type ReactRouterViteDevServer, |
| 58 | type ReactRouterViteModule, |
| 59 | type ResolvedViteBuildSlice, |
| 60 | } from "./ReactRouter.ts"; |
| 61 | |
| 62 | /** |
| 63 | * The structural subset of the e2e harness's `Options` this package reads. |
| 64 | */ |
| 65 | export interface HarnessOptions { |
| 66 | readonly reactRouter?: |
| 67 | | { readonly buildDirectory?: string | undefined } |
| 68 | | undefined; |
| 69 | } |
| 70 | |
| 71 | /** Map the harness's options onto {@link ReactRouterOptions}. */ |
| 72 | export const fromHarnessOptions = ( |
| 73 | options: HarnessOptions, |
| 74 | ): ReactRouterOptions => ({ |
| 75 | buildDirectory: options.reactRouter?.buildDirectory, |
| 76 | }); |
| 77 | |
| 78 | /** |
| 79 | * The e2e-harness factory contract |
| 80 | * (`framework: "@alchemy.run/frontend-frameworks/react-router"` in |
| 81 | * `e2e.config.ts`). |
| 82 | */ |
| 83 | const factory = ( |
| 84 | options: HarnessOptions, |
| 85 | ): Layer.Layer<Framework, never, FileSystem.FileSystem | Path.Path> => |
| 86 | layer(fromHarnessOptions(options ?? {})); |
| 87 | |
| 88 | export default factory; |