react-router-effect 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,284 @@
1
+ import { C as ReturnableDataError, _ as NameError, a as RegisteredMeta, g as LibraryHandled, h as IsAny, m as FailureResponse, o as RegisteredRecover, p as FactoryTypes, y as RouteHandlers } from "./route-data-CWBxnNAA.mjs";
2
+ import { Context, Effect, FileSystem, Layer, Option, Path, Scope } from "effect";
3
+ import { Register, RouterContextProvider, ServerBuild } from "react-router";
4
+ import { HttpPlatform, HttpRouter, HttpServerError, HttpServerRequest, HttpServerResponse } from "effect/http";
5
+ /** A React Router server build, or a function that loads it, as in `createRequestHandler`. */
6
+ type BuildSource = ServerBuild | (() => ServerBuild | Promise<ServerBuild>);
7
+ declare const ReactRouter_base: Context.ServiceClass<ReactRouter, "react-router-effect/ReactRouter", {
8
+ /**
9
+ * The build, when the layer loaded it once at startup: a build value, or
10
+ * a build function in production mode. `None` when the build loads for
11
+ * each request.
12
+ */
13
+ readonly build: Option.Option<ServerBuild>;
14
+ /**
15
+ * Answers the current request with React Router. The Scope is the
16
+ * request's scope: the resources that `loadContext` opens close with it.
17
+ */
18
+ readonly handle: Effect.Effect<HttpServerResponse.HttpServerResponse, HttpServerError.RequestError, HttpServerRequest.HttpServerRequest | Scope.Scope>;
19
+ }>;
20
+ /**
21
+ * React Router, as a service of the Effect HTTP app. `ReactRouter.layer`
22
+ * provides it, and `ReactRouter.routes` registers it on the app's router as
23
+ * the catch-all route.
24
+ *
25
+ * ```ts
26
+ * export const App = ReactRouter.routes.pipe(
27
+ * Layer.provide(
28
+ * ReactRouter.layer({
29
+ * build: () => import("virtual:react-router/server-build"),
30
+ * factory: routeFactory,
31
+ * mode: import.meta.env.MODE,
32
+ * }),
33
+ * ),
34
+ * );
35
+ * ```
36
+ *
37
+ * @stability unstable
38
+ */
39
+ export declare class ReactRouter extends ReactRouter_base {
40
+ /**
41
+ * Provides React Router. A build value, or a build function in production
42
+ * mode, loads when the layer builds. Provide one value of this layer to
43
+ * every layer that reads the service: two values load the build twice.
44
+ *
45
+ * @stability unstable
46
+ */
47
+ static readonly layer: <R = never>(options: ReactRouter.Options<R>) => Layer.Layer<ReactRouter, never, Exclude<R, Scope.Scope>>;
48
+ /**
49
+ * Registers React Router as the catch-all route of the app's router, on
50
+ * `*`, for every method of `HttpMethod.all` but HEAD. A route that the app
51
+ * registers itself wins over it, also a route on `/`, such as the
52
+ * prerendered home page of `ReactRouterAssets.layer`. A HEAD request uses
53
+ * the GET route of its path, React Router's or the app's own, as Express
54
+ * does. A method outside `HttpMethod.all` gets the router's 404. Register
55
+ * it at the root of the router: under a prefix, React Router does not get
56
+ * the path that it expects.
57
+ *
58
+ * @stability unstable
59
+ */
60
+ static readonly routes: Layer.Layer<never, never, HttpRouter.HttpRouter | ReactRouter | HttpRouter.Request<"Error", HttpServerError.InternalError> | HttpRouter.Request<"Error", HttpServerError.RequestParseError> | HttpRouter.Request<"Error", HttpServerError.RouteNotFound>>;
61
+ }
62
+ export declare namespace ReactRouter {
63
+ /**
64
+ * The options of {@link ReactRouter.layer}. `R` is the requirement of `loadContext`.
65
+ *
66
+ * @stability unstable
67
+ */
68
+ interface Options<R = never> {
69
+ /** The server build: `() => import("virtual:react-router/server-build")`. */
70
+ readonly build: BuildSource;
71
+ /** The route factory whose runner, runtime and error model route Effects use. */
72
+ readonly factory: {
73
+ readonly handlers: RouteHandlers;
74
+ };
75
+ /**
76
+ * React Router's server mode, such as `import.meta.env.MODE` in a Vite
77
+ * app. React Router runs in production mode for any mode but
78
+ * `development` and `test`, and so does the layer: it loads a build
79
+ * function for each request only in those two modes.
80
+ */
81
+ readonly mode: "development" | "production" | "test" | (string & {});
82
+ /**
83
+ * Makes React Router's load context for each request, as `getLoadContext`
84
+ * does for `@react-router/express`. Plain loaders and actions, and
85
+ * `handleRequest` in `entry.server.tsx`, read its values with
86
+ * `context.get`. Route Effects read services from their Effect context,
87
+ * so an app gives them services with router middleware, not here. The
88
+ * adapter adds its own keys to the provider. The Effect gets the services
89
+ * of `R` from the layer, and the services of the request, which win over
90
+ * the services of the layer. A defect answers an empty 500.
91
+ */
92
+ readonly loadContext?: ((request: HttpServerRequest.HttpServerRequest) => Effect.Effect<RouterContextProvider, never, R>) | undefined;
93
+ }
94
+ }
95
+ declare namespace assets_d_exports {
96
+ export { ClientBuildError, layer };
97
+ }
98
+ declare const ClientBuildError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
99
+ readonly _tag: "ClientBuildError";
100
+ } & Readonly<A>;
101
+ /**
102
+ * The layer cannot serve the client build: it cannot read the directory, or
103
+ * a file name has a `*`, which the router cannot match. The build's
104
+ * `assetsBuildDirectory` is relative to the working directory of the server,
105
+ * so `directory` is the path that it resolved to.
106
+ *
107
+ * @stability unstable
108
+ * @since 2.2.0
109
+ */
110
+ declare class ClientBuildError extends ClientBuildError_base<{
111
+ readonly message: string;
112
+ /** The resolved directory of the client build. */
113
+ readonly directory: string;
114
+ readonly cause: unknown;
115
+ }> {}
116
+ /**
117
+ * Registers the routes of the client build on the app's router, for GET and
118
+ * HEAD, under the build's `publicPath`.
119
+ *
120
+ * The hashed directory is the directory of the build's manifest URL, such as
121
+ * `/assets`. The build plugin writes the files with a content hash in their
122
+ * names there. Its files are cached for a year as immutable, and a request
123
+ * under it for a file that the directory does not have gets a 404. The
124
+ * files are served from that directory only, so a path with `..` does not
125
+ * reach the other files of the client build.
126
+ *
127
+ * Each other file gets its own route, and is cached for an hour. A directory
128
+ * with an `index.html`, such as a prerendered page, gets a route that serves
129
+ * its `index.html`, and its path without the trailing slash redirects. The
130
+ * layer serves no path with a segment that starts with a dot, such as
131
+ * `.vite/`, as `express.static` ignores dotfiles. A root `index.html`, such
132
+ * as a prerendered home page, gets the route `/`, which wins over the
133
+ * catch-all of `ReactRouter.routes`. Any other request goes on to the app's
134
+ * other routes.
135
+ *
136
+ * The layer reads the client build when it builds, so a file that something
137
+ * adds outside the hashed directory later is served after a restart. It
138
+ * fails with a {@link ClientBuildError} when it cannot read the client build
139
+ * directory, or when a file name has a `*`, which the router cannot match.
140
+ * A route of the app with the path of a file fails the server's start.
141
+ *
142
+ * The layer registers nothing for a build that loads for each request, such
143
+ * as a development build, since Vite serves the client there. It also
144
+ * registers nothing for a `publicPath` on another origin.
145
+ *
146
+ * The routes of this layer get the middleware that the app provides to this
147
+ * layer. To leave the server's request logger out of file requests:
148
+ *
149
+ * ```ts
150
+ * ReactRouterAssets.layer.pipe(Layer.provide(HttpRouter.disableLogger))
151
+ * ```
152
+ *
153
+ * @stability unstable
154
+ */
155
+ declare const layer: Layer.Layer<never, ClientBuildError, HttpRouter.HttpRouter | ReactRouter | FileSystem.FileSystem | Path.Path | HttpPlatform.HttpPlatform>;
156
+ /** The route modules React Router's typegen registers, keyed by route ID. */
157
+ type RegisteredRouteModules = Register extends {
158
+ readonly routeModules: infer Modules;
159
+ } ? Modules : {};
160
+ /** What an effect middleware may succeed with: React Router's response, or nothing. */
161
+ type MiddlewareResult = Response | void | undefined;
162
+ /** What a failure says to do, under its `react-router-effect` key. */
163
+ type FailureMessage = "This route Effect can fail with an error the route factory does not handle, or needs a service it does not provide. Catch the error in the Effect (for example with Effect.catchTag), add it to the factory's domain errors, or provide the service.";
164
+ /**
165
+ * One export that fails the check. `unhandledErrors` lists each error the
166
+ * effect can fail with that the factory does not handle, by its `_tag`.
167
+ * `missingServices` lists each service that neither the runtime nor the
168
+ * request context provides. `invalidResults` lists what a middleware succeeds
169
+ * with that is not a `Response` or nothing.
170
+ *
171
+ * It is an inline object type, not an interface, so the compiler prints its
172
+ * fields in the error rather than an alias name.
173
+ *
174
+ * @stability unstable
175
+ */
176
+ type RouteEffectFailure<Route, Export, Unhandled, Missing, Invalid> = {
177
+ readonly "react-router-effect": FailureMessage;
178
+ readonly route: Route;
179
+ readonly export: Export;
180
+ readonly unhandledErrors: Unhandled;
181
+ readonly missingServices: Missing;
182
+ readonly invalidResults: Invalid;
183
+ };
184
+ /**
185
+ * The failure of one route function, or `never` when it does not return an
186
+ * Effect or when its Effect is fully handled. An Effect whose error or
187
+ * service type is `any` comes from a mistake TypeScript already reports, so it
188
+ * is skipped rather than reported a second time.
189
+ */
190
+ type FunctionFailure<Route, Export, F, Handled, Provided, Result> = F extends ((...args: never[]) => Effect.Effect<infer A, infer E, infer R>) ? true extends IsAny<E> | IsAny<R> ? never : [Exclude<E, Handled>, Exclude<R, Provided>, Exclude<A, Result>] extends [never, never, never] ? never : {
191
+ readonly "react-router-effect": FailureMessage;
192
+ readonly route: Route;
193
+ readonly export: Export;
194
+ readonly unhandledErrors: NameError<Exclude<E, Handled>>;
195
+ readonly missingServices: Exclude<R, Provided>;
196
+ readonly invalidResults: Exclude<A, Result>;
197
+ } : never;
198
+ /** The failures of one route module's loader, action and middleware. */
199
+ type ModuleFailures<Route, Module, Handled, Provided> = (Module extends {
200
+ readonly loader: infer F;
201
+ } ? FunctionFailure<Route, "loader", F, Handled, Provided, unknown> : never) | (Module extends {
202
+ readonly action: infer F;
203
+ } ? FunctionFailure<Route, "action", F, Handled, Provided, unknown> : never) | (Module extends {
204
+ readonly middleware: ReadonlyArray<infer F>;
205
+ } ? FunctionFailure<Route, "middleware", F, Handled | FailureResponse, Provided, MiddlewareResult> : never);
206
+ /** The failures of every registered route module. */
207
+ type AllFailures<Modules, Handled, Provided> = { [Route in keyof Modules]: ModuleFailures<Route, Modules[Route], Handled, Provided>; }[keyof Modules];
208
+ /** The types of a route factory. */
209
+ type TypesOf<Factory> = Factory extends {
210
+ readonly "~types": infer Types;
211
+ } ? Types : never;
212
+ /** What one error handler's return recovers into, or `never` when it throws. */
213
+ type HandlerRecovered<Return> = Return extends ReturnableDataError<infer Body> ? Body : Return extends Effect.Effect<infer Success, infer _E, infer _R> ? Success : never;
214
+ /** The factory's recover map: each error tag whose handler recovers, and its data. */
215
+ type FactoryRecover<Returns> = { [Tag in keyof Returns as [HandlerRecovered<Returns[Tag]>] extends [never] ? never : Tag]: HandlerRecovered<Returns[Tag]>; };
216
+ /** True when each type is assignable to the other. */
217
+ type SameType<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
218
+ /**
219
+ * A disagreement between the `Register` of `react-router-effect` and the
220
+ * factory, which would type plain Effect routes' data wrongly.
221
+ *
222
+ * @stability unstable
223
+ */
224
+ interface RegisterMismatch<Key, Factory, Registered> {
225
+ readonly register: Key;
226
+ readonly factory: Factory;
227
+ readonly registered: Registered;
228
+ }
229
+ /** The registration mismatches of a factory's types. */
230
+ type RegisterMismatches<Returns, Meta> = (SameType<FactoryRecover<Returns>, RegisteredRecover> extends true ? never : RegisterMismatch<"recover", FactoryRecover<Returns>, RegisteredRecover>) | (SameType<Meta, RegisteredMeta> extends true ? never : RegisterMismatch<"actionMeta", Meta, RegisteredMeta>);
231
+ /** Every failure: the routes', then the registration's. */
232
+ type Failures<Modules, Types> = Types extends FactoryTypes<infer DomainError, infer Returns, infer Services, infer Meta> ? AllFailures<Modules, LibraryHandled<DomainError>, Services> | RegisterMismatches<Returns, Meta> : never;
233
+ /**
234
+ * The failures of every Effect route function across the route modules React
235
+ * Router's typegen registers, and the registration mismatches, as objects.
236
+ * `never` when everything is handled. `RouteEffectCheck` reports them.
237
+ *
238
+ * @stability unstable
239
+ */
240
+ type RouteEffectFailures<Factory, Modules = RegisteredRouteModules> = Failures<Modules, TypesOf<Factory>>;
241
+ /** A printable name for an error tag or another unhandled error type. */
242
+ type ErrorName<Name> = Name extends string ? Name : "an untagged error";
243
+ /** A printable name for a service: its key, such as `"app/Database"`. */
244
+ type ServiceName<Service> = Service extends {
245
+ readonly key: infer Key extends string;
246
+ } ? Key : "a service without a string key";
247
+ /** The diagnostic lines of one failure, one per error, service or result. */
248
+ type FailureLines<Failure> = Failure extends {
249
+ readonly route: infer Route extends string | number | symbol;
250
+ readonly export: infer Export extends string;
251
+ readonly unhandledErrors: infer Unhandled;
252
+ readonly missingServices: infer Missing;
253
+ readonly invalidResults: infer Invalid;
254
+ } ? (Unhandled extends unknown ? `${Route & string}#${Export} must handle ${ErrorName<Unhandled>}` : never) | (Missing extends unknown ? `${Route & string}#${Export} needs a provider for ${ServiceName<Missing>}` : never) | ([Invalid] extends [never] ? never : `${Route & string}#${Export} must succeed with a Response or nothing`) : Failure extends {
255
+ readonly register: infer Key extends string;
256
+ } ? `the Register of react-router-effect: ${Key} does not match the route factory` : never;
257
+ /**
258
+ * Checks every loader, action and middleware that returns an Effect, across
259
+ * the route modules React Router's typegen registers. Each failure is a
260
+ * required property whose name says what to fix, so assigning `{}` fails to
261
+ * compile with a list such as:
262
+ *
263
+ * ```text
264
+ * Type '{}' is missing the following properties from type ...:
265
+ * "routes/billing#loader must handle PlaidApiError",
266
+ * "routes/admin#middleware needs a provider for app/Session"
267
+ * ```
268
+ *
269
+ * ```ts
270
+ * import type { RouteEffectCheck } from "react-router-effect/server";
271
+ *
272
+ * export const routeEffects: RouteEffectCheck<typeof routeFactory> = {};
273
+ * ```
274
+ *
275
+ * An Effect may fail with the factory's domain errors, the library's `Respond`
276
+ * errors, and `HttpServerRespondable` errors, and require the services of the
277
+ * factory's runtime and request context. A middleware may also fail with what
278
+ * its `next()` fails with. The check also fails when the `Register` of
279
+ * `react-router-effect` disagrees with the factory.
280
+ *
281
+ * @stability unstable
282
+ */
283
+ type RouteEffectCheck<Factory, Modules = RegisteredRouteModules> = { readonly [Line in FailureLines<RouteEffectFailures<Factory, Modules>>]: Line; };
284
+ export { assets_d_exports as ReactRouterAssets, type RegisterMismatch, type RouteEffectCheck, type RouteEffectFailure, type RouteEffectFailures };