fix: inject grouped route codecs
This commit is contained in:
@@ -42,7 +42,6 @@ import {
|
||||
buildRouteUrlFromDefinition,
|
||||
parseRouteInputFromContract,
|
||||
type RouteCodecRegistry,
|
||||
type RouteId,
|
||||
} from "./route-codecs.ts";
|
||||
import {
|
||||
ROUTE_CODECS,
|
||||
@@ -142,12 +141,12 @@ function RouteLifecycle({
|
||||
return null;
|
||||
}
|
||||
|
||||
function CanonicalRouteRedirect({
|
||||
function CanonicalRouteRedirect<RouteIdValue extends string>({
|
||||
input,
|
||||
definition,
|
||||
codecs,
|
||||
}: {
|
||||
input: ParsedRouteInput;
|
||||
input: ParsedRouteInput<RouteIdValue>;
|
||||
definition: RouteDefinition;
|
||||
codecs: RouteCodecRegistry;
|
||||
}) {
|
||||
@@ -251,14 +250,14 @@ function ProtectedRoute({
|
||||
);
|
||||
}
|
||||
|
||||
function RegisteredRoute({
|
||||
function RegisteredRoute<RouteIdValue extends string>({
|
||||
routeId,
|
||||
buildId,
|
||||
definition,
|
||||
runtime,
|
||||
codecs,
|
||||
}: {
|
||||
routeId: RouteId;
|
||||
routeId: RouteIdValue;
|
||||
buildId: string;
|
||||
definition: RouteDefinition;
|
||||
runtime: GroupedRouteRuntimeDefinition;
|
||||
@@ -276,7 +275,7 @@ function RegisteredRoute({
|
||||
search,
|
||||
);
|
||||
if (!parsed.success) return <InvalidRouteSurface code={parsed.code} />;
|
||||
const routeInput = parsed.data as ParsedRouteInput;
|
||||
const routeInput = parsed.data;
|
||||
const RuntimeComponent = runtime.Component;
|
||||
|
||||
const content = (
|
||||
@@ -334,7 +333,7 @@ export function createGroupedRouteObjects(
|
||||
runtime: GroupedRouteRuntime,
|
||||
layouts: GroupedRouteLayouts,
|
||||
buildId: string,
|
||||
codecs: RouteCodecRegistry = ROUTE_CODECS,
|
||||
codecs: RouteCodecRegistry,
|
||||
): RouteObject[] {
|
||||
for (const routeId of Object.keys(runtime)) {
|
||||
if (!registry[routeId]) {
|
||||
@@ -347,7 +346,7 @@ export function createGroupedRouteObjects(
|
||||
STUDIO: [],
|
||||
};
|
||||
for (const definition of Object.values(registry)) {
|
||||
const routeId = definition.routeId as RouteId;
|
||||
const routeId = definition.routeId;
|
||||
const routeRuntime = runtime[definition.routeId];
|
||||
if (!routeRuntime) {
|
||||
throw new TypeError(`Missing route runtime: ${definition.routeId}`);
|
||||
@@ -411,6 +410,7 @@ export function AppRouter({
|
||||
STUDIO: <Outlet />,
|
||||
},
|
||||
buildId,
|
||||
ROUTE_CODECS,
|
||||
),
|
||||
{ basename },
|
||||
),
|
||||
|
||||
@@ -24,19 +24,9 @@ type RouteCodec = Readonly<{
|
||||
}>;
|
||||
|
||||
export type RouteCodecRegistry = Readonly<Record<string, RouteCodec>>;
|
||||
export type ContractRouteInputResult =
|
||||
| Readonly<{
|
||||
success: true;
|
||||
data: Readonly<{
|
||||
routeId: string;
|
||||
params: Readonly<Record<string, unknown>>;
|
||||
search: Readonly<Record<string, unknown>>;
|
||||
}>;
|
||||
}>
|
||||
| Readonly<{
|
||||
success: false;
|
||||
code: "ROUTE_PARAMS_INVALID" | "ROUTE_SEARCH_INVALID";
|
||||
}>;
|
||||
export type ContractRouteInputResult<
|
||||
RouteIdValue extends string = string,
|
||||
> = RouteInputResult<RouteIdValue>;
|
||||
|
||||
function codecById(codecId: string, codecs: RouteCodecRegistry = ROUTE_CODECS) {
|
||||
const codec = codecs[codecId];
|
||||
@@ -55,16 +45,16 @@ export function parseRouteInput(
|
||||
ROUTE_CODECS,
|
||||
rawParams,
|
||||
rawSearch,
|
||||
) as RouteInputResult;
|
||||
);
|
||||
}
|
||||
|
||||
export function parseRouteInputFromContract(
|
||||
routeId: string,
|
||||
export function parseRouteInputFromContract<RouteIdValue extends string>(
|
||||
routeId: RouteIdValue,
|
||||
definition: Pick<RouteDefinition, "paramsSchema" | "searchSchema">,
|
||||
codecs: RouteCodecRegistry,
|
||||
rawParams: Readonly<Record<string, string | undefined>>,
|
||||
rawSearch: URLSearchParams,
|
||||
): ContractRouteInputResult {
|
||||
): ContractRouteInputResult<RouteIdValue> {
|
||||
const params = codecById(
|
||||
definition.paramsSchema ?? "none",
|
||||
codecs,
|
||||
|
||||
@@ -2,14 +2,14 @@ import { ROUTE_RUNTIME_CONTRACT } from "../../features/installed-feature-contrac
|
||||
|
||||
export type RouteId = keyof typeof ROUTE_RUNTIME_CONTRACT;
|
||||
|
||||
export type ParsedRouteInput = Readonly<{
|
||||
routeId: RouteId;
|
||||
export type ParsedRouteInput<RouteIdValue extends string = RouteId> = Readonly<{
|
||||
routeId: RouteIdValue;
|
||||
params: Readonly<Record<string, unknown>>;
|
||||
search: Readonly<Record<string, unknown>>;
|
||||
}>;
|
||||
|
||||
export type RouteInputResult =
|
||||
| Readonly<{ success: true; data: ParsedRouteInput }>
|
||||
export type RouteInputResult<RouteIdValue extends string = RouteId> =
|
||||
| Readonly<{ success: true; data: ParsedRouteInput<RouteIdValue> }>
|
||||
| Readonly<{
|
||||
success: false;
|
||||
code: "ROUTE_PARAMS_INVALID" | "ROUTE_SEARCH_INVALID";
|
||||
|
||||
@@ -4,15 +4,15 @@ import {
|
||||
useContext,
|
||||
} from "react";
|
||||
|
||||
import type { ParsedRouteInput } from "./route-contract.ts";
|
||||
import type { ParsedRouteInput, RouteId } from "./route-contract.ts";
|
||||
|
||||
const RouteInputContext = createContext<ParsedRouteInput | null>(null);
|
||||
const RouteInputContext = createContext<ParsedRouteInput<string> | null>(null);
|
||||
|
||||
export function RouteInputProvider({
|
||||
export function RouteInputProvider<RouteIdValue extends string>({
|
||||
input,
|
||||
children,
|
||||
}: Readonly<{
|
||||
input: ParsedRouteInput;
|
||||
input: ParsedRouteInput<RouteIdValue>;
|
||||
children: ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
@@ -22,8 +22,10 @@ export function RouteInputProvider({
|
||||
);
|
||||
}
|
||||
|
||||
export function useRouteInput(): ParsedRouteInput {
|
||||
export function useRouteInput<
|
||||
RouteIdValue extends string = RouteId,
|
||||
>(): ParsedRouteInput<RouteIdValue> {
|
||||
const input = useContext(RouteInputContext);
|
||||
if (!input) throw new Error("Registered route input is required");
|
||||
return input;
|
||||
return input as ParsedRouteInput<RouteIdValue>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user